References, Heap Allocation and Memory Management
21.1 References
References &T can't be nil in safe code (unsafe { nil } is needed). Prefer ?&T options for nullable references.
Taking the address of a stack value that escapes automatically moves it to the heap (escape analysis).
struct Node {
mut:
value int
next &Node = unsafe { nil }
}
fn main() {
mut a := &Node{value: 1} // heap allocation; a is &Node
a.next = &Node{value: 2}
println(a.next.value)
b := a // copies the reference: both point to the same node
_ = b
if a.next.next == unsafe { nil } {
println('end')
}
}21.2 Value vs Reference Semantics
Primitives, structs Value (copied) Arrays, maps, strings Reference to shared data internally. Use .clone() for independent copies. Strings are immutable.
21.3 Memory Management Modes
Boehm GC (default) — / -gc boehm Conservative tracing GC (bundled). Safe and convenient.
Autofree (experimental) The compiler inserts frees for most objects. The GC handles the rest.
Manual / no GC You manage memory (free(), unsafe) Arena prealloc
Bump allocator that never frees (short-lived CLI tools) Tools: -d use_libbacktrace, -cg (debug), and valgrind / AddressSanitizer with -gc none or -cc clang -cflags -fsanitize=address.
// Manual freeing (with -gc none or autofree)
mut s := []int{len: 1000}
unsafe { s.free() }
// Custom free method
@[unsafe]
fn (mut r Resource) free() { /* release C handles */ }21.4 Lifetimes and Escape Analysis (Simplified)
V doesn't have a borrow checker. Safety comes from immutability, GC/autofree, bounds checking, and restrictions such as no pointer arithmetic outside unsafe.