Part 15: Memory

Until now every value had a size the compiler knew and a home it chose. This part opens the box underneath: pointers that hold addresses, memory you ask for while the program runs, and the layout of the bytes themselves. It starts with the rawest tools, where every rule is yours to keep, and ends with allocators that keep most of those rules for you — so by the end you know both what they do and why they exist.

What you will learn

  • Taking an address with @, reaching through it with *, and the difference between *T and *var T.
  • Returning extra answers through an out-parameter, and why a fallible is usually better.
  • Asking for memory with Alloc, clearing it with Zero and returning it with Free.
  • Pointer arithmetic, and turning a pointer and a count into an ordinary slice with p[..n].
  • Optional pointers (*T)? versus pointers to optionals *T?, and why null is not none.
  • How big a type is and how it is aligned, and the padding a struct carries.
  • Unions, which lay several members over the same bytes.
  • The Allocator interface, and four ways to stand behind it: SystemAllocator, Arena, FixedBuffer and Pool — plus Box<T>, which owns one allocated value.
  • Wiping a secret with Zeroize, a clear the compiler never removes.

The allocator family

flowchart LR
    code["your code,<br/>written against Allocator"] --> iface{{"Allocator<br/>Allocate · Deallocate · Reallocate"}}
    box["Box&lt;T&gt;<br/>owns one value"] --> iface
    iface --- sys["SystemAllocator<br/>pages from the system"]
    iface --- arena["Arena<br/>a moving marker; Reset frees all"]
    iface --- fixed["FixedBuffer<br/>storage you own; a hard limit"]
    iface --- pool["Pool<br/>fixed-size blocks, reused"]
    sys -. "backs" .-> arena
    sys -. "backs" .-> pool

Code that takes an Allocator works with any of the four. SystemAllocator asks the operating system and is usually the one an arena or a pool draws its large blocks from; FixedBuffer draws on nothing but the storage you give it.

Lessons

LessonWhat you will learn
15.1Pointerthe difference between *T and *var T, and taking an address with @
15.2Out parameterreturn extra information through a pointer parameter
15.3Raw memoryallocate, use and free memory by hand (Alloc, Zero, Free)
15.4Pointer arithmeticstep a pointer through memory one element at a time
15.5Pointer sliceturn a pointer and a length into a slice
15.6Optional pointer*T? and (*T)?: a pointer to an optional, or an optional pointer
15.7Layouthow big a type is and how it is aligned: sizeof and alignof
15.8Unionoverlay one piece of storage with several types, and why that needs care
15.9Allocatorallocate through the Allocator interface instead of straight from the system
15.10Boxown one value allocated on the heap
15.11Arenaallocate many values and free them all at once
15.12Fixed bufferallocate from a buffer you provide
15.13Poolreuse fixed-size blocks instead of allocating new ones
15.14Zeroizeclear sensitive memory explicitly

Before you start

This part leans on much of what came before. Pointers build on Reference from Part 6; allocators report failure with the fallibles of Part 9: Errors; cleaning up relies on Destructor, Move and Defer from Part 11: Ownership; and Allocator is used as in Interface value from Part 12: Interfaces. Each lesson's package is in the Examples repository's Memory/ folder:

cd Examples/Memory/Pointer
rux run

After this part

Part 16: Numbers looks at numbers in depth — wide integers, limits, bit operations, checked and wrapping arithmetic. After Part 16 you are ready for the checkpoint projects Circle and Quadratic. Then Part 17: Collections puts this part to work: its containers take an Allocator and grow by asking it for memory.

For the full rules, see Pointers, Pointer arithmetic, Slices and pointers and Unions in the Rux Reference, and the Memory package in the API reference.