Memory Overview
Current implementation
The compiler currently implements scope-based automatic cleanup for strings and structs with string fields. All other heap memory is manual (mem.alloc / mem.free + defer).
Managed types
The compiler classifies locals as “managed” if they are:
- String type (dynamic string descriptors)
- Structs that contain string fields
Managed locals get automatic cleanup when they go out of scope.
Scope-based cleanup
fn process() {
let name = build_name(); // managed string
let data = read_input(); // managed string
// both are freed automatically at scope exit
}The compiler inserts string_drop calls at every scope exit point (end of block, return, early return). Drop order is reverse declaration order.
Copy semantics
Assigning a managed value to a new variable produces a deep copy:
let a = "hello";
let b = a; // b is an independent copy (deep copy if dynamic)Static strings (string literals, cap == 0) are shallow-copied (just the pointer). Dynamic strings (built at runtime, cap > 0) are heap-duplicated.
Move on return
When a function returns a managed local, the compiler skips the drop for that local — the value is “moved” to the caller:
fn make_greeting(name: *u8) -> []u8 {
let s = str.concat("Hello, ", name);
return s; // no drop — ownership transfers to caller
}Manual allocation
For raw memory, use the mem module:
import mem from "mem";
let ptr: *u8 = mem.alloc(1024);
defer mem.free(ptr, 1024);Available functions:
| Function | Description |
|---|---|
mem.alloc(size: u64) -> *u8 | Allocate bytes |
mem.free(ptr: *u8, size: u64) | Free allocation |
mem.set(dst, val, count) | Fill memory |
mem.copy(dst, src, count) | Copy bytes (non-overlapping) |
mem.move(dst, src, count) | Copy bytes (overlapping safe) |
mem.zero(dst, count) | Zero-fill |
mem.compare(a, b, count) -> i32 | Compare bytes |
mem.equal(a, b, count) -> bool | Equality check |
Defer for cleanup
Use defer to schedule cleanup for manual resources:
let file = os.open("data.bin");
defer os.close(file);
let buf: *u8 = mem.alloc(4096);
defer mem.free(buf, 4096);See Defer & Errdefer for details.
Last modified: