Heap & Resource Management
Monty uses a custom heap implementation for managing Python objects with reference counting and garbage collection. This page documents the key types and traits related to heap management.Heap
The heap is the central memory arena for allocating and managing heap-allocated Python values.Key Responsibilities
- Allocation: Allocates
HeapDataobjects and returnsHeapIdreferences - Reference Counting: Tracks reference counts for all heap objects
- Garbage Collection: Periodically reclaims unreachable objects
- Resource Tracking: Uses a
ResourceTrackerto enforce memory and allocation limits
Methods
allocate()
Allocates a new heap object and returns itsHeapId.
The data to allocate on the heap
Result<HeapId, ResourceError>
Returns the heap ID or a resource error if limits are exceeded
get()
Retrieves a reference to a heap object by itsHeapId.
The heap ID of the object to retrieve
&HeapData
An immutable reference to the heap data
get_mut()
Retrieves a mutable reference to a heap object by itsHeapId.
The heap ID of the object to retrieve
&mut HeapData
A mutable reference to the heap data
clone_with_heap()
Clones a value while properly incrementing reference counts for any heap-allocated components.The value to clone
Value
The cloned value with incremented reference counts
drop_with_heap()
Drops a value while properly decrementing reference counts for any heap-allocated components. This is the correct way to drop aValue that may contain heap references.
The value to drop (consumes ownership)
Mutable reference to the heap for decrementing reference counts
HeapId
An opaque identifier for a heap-allocated object. Heap IDs are used to reference objects in the heap without directly holding pointers. This enables safe serialization, garbage collection, and reference counting.HeapData
The actual data stored in the heap. This is an enum containing all heap-allocated Python types:Heap-allocated string
Heap-allocated bytes object
Heap-allocated list
Heap-allocated tuple
Heap-allocated dictionary
Heap-allocated set
Heap-allocated frozenset
Heap-allocated arbitrary-precision integer
Heap-allocated named tuple
Heap-allocated dataclass instance
Heap-allocated exception object
Heap-allocated path object
Heap-allocated cell (for closures)
Heap-allocated closure
Heap-allocated coroutine
Heap-allocated range object
Heap-allocated iterator
Heap-allocated module
ResourceTracker
A trait for tracking and enforcing resource limits during execution.Methods
track_allocation()
Called before each heap allocation to check if limits allow the allocation.The size of the allocation in bytes
Result<(), ResourceError>
Returns
Ok(()) if the allocation is allowed, or a ResourceError if limits are exceededcheck_time()
Called periodically to check if execution time limits have been exceeded.Result<(), ResourceError>
Returns
Ok(()) if execution should continue, or a ResourceError if time limits are exceededImplementations
NoLimitTracker
A no-op resource tracker that allows unlimited allocations and execution time.Custom Trackers
You can implement your ownResourceTracker to enforce custom limits:
PyTrait
The core trait implemented by all Python types (Value, HeapData).
Methods
py_type()
Returns the Python type of this value.Type
The type enum variant (e.g.,
Type::Int, Type::Str)py_len()
Returns the length of this value if it’s a sequence or collection.Option<usize>
The length, or
None if the type doesn’t support len()py_bool()
Returns the truthiness of this value according to Python’s truth testing rules.bool
True if the value is truthy
py_repr()
Returns therepr() string for this value.
Cow<'static, str>
The repr string (may be owned or borrowed)
py_str()
Returns thestr() string for this value.
Cow<'static, str>
The str string (may be owned or borrowed)
Reference Counting Safety
All types that implementDropWithHeap hold heap references and must be cleaned up correctly on every code path. There are three mechanisms for ensuring this:
1. defer_drop! macro (preferred)
The simplest and safest approach. Use defer_drop! to bind a value into a guard that automatically drops it when scope exits.
defer_drop_mut! when you need a mutable reference:
2. HeapGuard (when you need control)
Use HeapGuard directly when you need to conditionally extract the value instead of dropping it.
