You have seen pointers, stack versus heap, and lifetime rules. Now we connect those ideas to how the CPU actually loads data: alignment, padding, and layouts that keep cache lines full.
Cache hierarchy in 60 seconds: CPU registers and L1 caches are fastest (roughly single-digit to low tens of cycles). L2/L3 are larger but slower. Main DRAM is orders of magnitude slower than L1. The CPU always moves data in cache lines (often 64 bytes on x86_64 and ARM). A cache miss to DRAM can cost hundreds of cycles, enough to hide many arithmetic instructions. Data layout in this lesson, container choice (Lesson 6.1), and false sharing (Lesson 9.6) all exist to keep useful bytes in the levels the core can reach quickly.
Let's look at custom alignment, false sharing foundations, and Data Oriented Design patterns.
Structure Padding and Member Reordering
To understand alignment, we must look at how the compiler lays out custom structures in memory. When you declare a structure, the compiler must ensure that every member variable satisfies its own alignment requirement. To achieve this, it inserts unused bytes of memory called padding between members.
Consider these two structures containing the exact same data types. The first structure is unaligned, forcing the compiler to pad it to 12 bytes; the second reorders members, shrinking the footprint to 8 bytes:
By sorting members from largest to smallest alignment requirements, we can dramatically shrink the memory footprint of our structures and fit more elements into CPU cache lines.
Hardware Alignment & Structure Padding
Click toggle below to see how compiler reordering packs members into smaller cache line boundaries.
Unaligned Layout: The compiler must align the 4-byte int b to a multiple of 4 bytes. Thus, 3 bytes of silent padding are added after char a. Another 3 bytes are added at the end so the entire struct is divisible by the largest member alignment. Total: 12 Bytes.
The alignof and alignas Keywords
Every data type has an alignment requirement (usually equal to its size). The CPU expects a 4 byte integer to reside at a memory address that is a multiple of 4. You can query a type's alignment using alignof.
Sometimes, you need to force a structure to align to a specific boundary (like a 64 byte cache line) for SIMD vectorization or multithreading performance. C++ provides the alignas specifier:
SIMD Alignment and alignas(32)
AVX instructions process 256 bits (32 bytes) of data simultaneously. Lesson 9.8 covers SIMD auto-vectorization in depth; for now, know that CPUs prefer 32-byte-aligned addresses for the fastest loads, though unaligned access (vmovups) still works with a penalty.
By using alignas(32) on your arrays or structures, you tell the compiler the data is aligned. That enables fast vmovaps (aligned move) instructions instead of slower vmovups (unaligned move) on many targets.
Why Structure Layout Matters (AoS vs SoA)
When you create an array of objects, the standard C++ object oriented approach is an Array of Structs (AoS). You define an entity, then make an array of them.
While this is logically clean, it is physically disastrous for hardware performance if you only need to process one specific field across all entities. When the CPU loads an entity from RAM, it pulls a 64 byte chunk of adjacent data (a cache line). If you only want to update the position, you are wasting cache bandwidth loading velocity, color, and name.
Data Oriented Design: Struct of Arrays (SoA)
To achieve maximum hardware performance (common in high-performance engines such as Unity DOTS and custom ECS designs), systems engineers use a Struct of Arrays (SoA) layout. You invert the structure, storing properties in separate, flat arrays:
With the SoA layout, if you write a loop to update all posX values, the CPU cache line will pull in exactly 16 posX floats at a time, completely filling the cache with useful data. Zero memory bandwidth is wasted on colors or velocities. This layout is also perfectly structured for SIMD auto-vectorization (Lesson 9.8).
* The Grocery Bag Metaphor: AoS is like packing each grocery bag with exactly one apple, one banana, and one carton of milk (representing one entity). If you just want to eat all the apples, you have to open every single bag. SoA is like packing all the apples into one giant bag, all bananas into another. If you want apples, you grab the apple bag and feast efficiently.