Skip to content

Chapter 3: Pointers & Memory

Understanding how Go manages memory helps you write more efficient code and avoid common pitfalls. Let’s explore pointers, stack vs heap allocation, and escape analysis.

Go manages memory automatically through garbage collection, but understanding pointers and memory allocation helps you write efficient code. Unlike C, Go pointers are safe - no pointer arithmetic, no manual memory management. But unlike high-level languages that hide pointers entirely, Go gives you control when you need it.

This chapter covers pointer fundamentals, when to use pointers vs values, stack vs heap allocation, and escape analysis. You’ll learn how Go decides where to allocate memory and how to write code that works with the runtime rather than against it.

A pointer holds the memory address of a value. Use & to get an address and * to dereference it. Pointers let you share data without copying and modify values across function boundaries.

Go pointers are restricted for safety: no pointer arithmetic, no casting arbitrary addresses to pointers. This prevents entire categories of bugs common in C. You get the benefits of pointers without the danger.

Use pointers when you need to:

  1. Modify a value passed to a function
  2. Avoid copying large structs
  3. Share data between goroutines
  4. Signal optional values (nil pointer)

Go automatically decides where to allocate memory:

  • Stack: Fast, automatic cleanup, limited size
  • Heap: Slower, garbage collected, unlimited size

Escape analysis is the compiler pass that decides whether a value can live on the stack or must be heap-allocated. The rule is easy to state - a value escapes if the compiler cannot prove that nothing references it after the function returns - but the answer for any particular line depends on inlining and on the call site. That makes it very easy to guess wrong, so this section shows the compiler’s real verdict rather than intuition.

Always check for nil before dereferencing:

Field order in structs affects memory usage due to alignment:

Slices are already reference types - they contain a pointer to the underlying array:

  1. Use pointers to modify - pass by pointer when the function needs to change the value
  2. Use pointers for large structs - avoid copying overhead
  3. Escape analysis - the compiler decides stack vs heap allocation, per call site and after inlining; read -gcflags=-m instead of guessing
  4. Check for nil - always validate pointers before use
  5. Order struct fields - largest to smallest minimizes padding
  6. Slices are references - they already point to underlying data

Optimize Struct Memory

easy

Given a struct with poor memory layout, reorder its fields to minimize size. Print both the original and optimized struct sizes using unsafe.Sizeof.


Pointer and allocation decisions show up everywhere once shared state is involved. These batteries exercise them directly:


Chapter in progress
0 / 14 chapters completed

Next up: Chapter 4: Goroutines & Channels