Memory Model
Mux uses reference counting for deterministic memory management. This document describes the memory model in detail.
Overview
Mux provides automatic memory management through atomic reference counting (RC):
- No manual
freeordelete - No garbage collector pauses
- Deterministic cleanup when references go out of scope
- Thread-safe reference count operations
Memory Layout
Heap Allocation
All non-primitive values are heap-allocated
Value Types
| Type | Storage | Memory Management |
|---|---|---|
int, float, bool, char | Inline (boxed in Value enum) | Reference counted |
string | Heap-allocated UTF-8 | Reference counted |
list<T> | Heap-allocated vector | Reference counted |
map<K,V> | Heap-allocated BTreeMap | Reference counted |
tuple<K,V> | Heap-allocated object | Reference counted |
set<T> | Heap-allocated BTreeSet | Reference counted |
optional<T>, result<T,E> | Boxed enum | Reference counted |
| Class instances | Heap-allocated object | Reference counted |
References (&T) | Pointer | Not RC'd (borrowed) |
Reference Counting Operations
Increment (mux_rc_inc the reference count when)
Increments creating a new reference:
When increment happens:
- Variable assignment
- Function argument passing
- Adding to collection
- Returning from function
Decrement (mux_rc_dec)
Decrements the reference count when a reference goes out of scope:
When decrement happens:
- Variable assignment (old value)
- Function return (local variables)
- Scope exit
- Collection element removal
Cleanup
When mux_rc_dec returns true, the refcount reached zero and memory is freed:
- For classes with destructors: call destructor
- Free the allocation
Scope-Based Tracking
The compiler generates cleanup code using a scope stack:
- Enter scope ->
push_rc_scope()(function entry, if-block, loop-body, match-arm) - Track variable ->
track_rc_variable(name, alloca)for each RC-allocated variable - Exit scope ->
generate_all_scopes_cleanup()iterates through all scopes in reverse order
Example: Scope Cleanup
Early Returns
Collections and Memory
Collections contain RC-allocated values. When freed:
- Collection's refcount reaches zero
- Collection's container (
Vec<Value>, etc.) is dropped - Each contained
Valuehas its refcount decremented - Nested collections are freed recursively
Nested Collections
Cleanup order:
- Outer list refcount -> 0
- Drop outer list
- Each map's refcount -> 0
- Drop each map
- Each inner list's refcount -> 0
- Drop inner lists
- All strings freed
Value Semantics
Reference vs Value
References (&T)
References provide non-owning pointers to values:
Reference Rules
- References are non-nullable
- No reference arithmetic
- References do not affect reference counts
- optional references:
optional<&T>
Memory Safety
No Use-After-Free
Memory is only freed when all references are gone:
No Double-Free
Reference counting prevents double-free:
Performance Characteristics
| Operation | Complexity |
|---|---|
| Allocation | O(1) amortized |
| Clone (increment) | O(1) atomic |
| Drop (decrement) | O(1) atomic |
| Clone collection | O(n) copy all elements |
| Clone map/set | O(n log n) insert all elements |
Thread Safety
Reference count operations use atomic operations:
// mux_rc_inc
fn rc_inc(ptr: *mut Value) {
let header = get_ref_header(ptr);
header.ref_count.fetch_add(1, Ordering::AcqRel);
}
// mux_rc_dec
fn rc_dec(ptr: *mut Value) -> bool {
let header = get_ref_header(ptr);
if header.ref_count.fetch_sub(1, Ordering::AcqRel) == 1 {
// Last reference - free memory
free(ptr);
true
} else {
false
}
}See Also
- Statements - Statement memory semantics
- Expressions - Expression value categories
- Classes - Class memory behavior