Course contentsShow
← Rust
Lesson 1704 of 1,91015. Performance and Architectural EngineeringFree lesson

The Cost of Box and Indirection

Analyze how pointer chasing affects heap fragmentation and dereference performance.

In this lesson, you will learn how Box<T> introduces performance overhead through pointer indirection and its impact on memory locality and CPU cache efficiency.

The Cost of Indirection

When you wrap a type in Box<T>, you are moving the data from the stack to the heap and leaving a pointer on the stack. While this is necessary for recursive data structures or trait objects, it introduces two distinct performance penalties: pointer chasing and memory fragmentation.

Pointer Chasing and Cache Misses

A Box is essentially a pointer. When the CPU needs to access the data inside a Box, it must perform a dereference. If the data is not already in the CPU cache, the processor must wait for a memory controller to fetch the data from RAM.

Consider a vector of structs:

// Contiguous in memory (Cache-friendly)
let vec_a: Vec<Point> = vec![Point { x: 1, y: 2 }; 1000];

// Indirection (Pointer chasing)
let vec_b: Vec<Box<Point>> = vec![Box::new(Point { x: 1, y: 2 }); 1000];

In vec_a, the points are stored contiguously. When the CPU loads vec_a[0], the hardware prefetcher speculatively loads vec_a[1] into the cache. In vec_b, the vector only contains pointers. The points themselves might be scattered across the heap. Accessing each Box requires a separate memory request, significantly increasing the probability of a cache miss.

Heap Fragmentation

Every time you create a Box, the allocator must find a suitable block of memory on the heap. Over time, as you allocate and deallocate various sizes of Box<T>, the heap becomes "fragmented"—riddled with small, non-contiguous holes.

This fragmentation hurts performance in two ways:

  1. Allocation Latency: The allocator must work harder to find a fit for new requests.
  2. Reduced Spatial Locality: Data that was logically created together becomes physically separated in memory, preventing the CPU from effectively utilizing cache lines.

While Box is a powerful tool for ownership and trait polymorphism, overusing it for small, frequently accessed objects can lead to "pointer-heavy" code that spends more time waiting for memory than performing computation.

Key Takeaway: Excessive use of Box destroys data locality and forces the CPU to stall on memory latency, turning a high-performance system into one bounded by heap management and cache misses.