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.