Skip to content

Memory alignment and padding

How base addresses and strides determine alignment, when padding helps, and why cache-line splits are a separate question.

Memory alignment requires a starting byte address to be a multiple of a specified number of bytes. Padding is space reserved in a memory layout that carries no payload. It can place a field or the next record on a required boundary. In a market-data parser, an aligned receive buffer can still contain records whose starts are unsuitable for a typed read. Each record has its own offset within the buffer. The Rust Reference — Type layout

One aligned base, two strides

Suppose three fictional quote records each carry 24 bytes of payload, and the consumer wants each record to start on a 16-byte boundary. Both layouts start at address 0x1000. This example specifies the layout of a byte buffer. A native type's layout follows its language and target rules.
The stride is the distance in bytes between consecutive starts. With base address bb, stride ss and zero-based index ii, the start is b+isb + is. If bb is a multiple of 16 and there are at least two records, every start is aligned exactly when ss is also a multiple of 16. In this buffer, the smallest such stride that fits the 24-byte payload is 32 bytes.
LayoutFirst three starting addressesRemainders on division by 16
Packed, 24-byte stride0x1000, 0x1018, 0x10300, 8, 0
Padded, 32-byte stride0x1000, 0x1020, 0x10400, 0, 0

The padded layout reserves 8 extra bytes in each slot, including the last. Three slots therefore take 96 bytes to store the same 72 bytes of payload.

Packed 24-byte records start at offsets 0, 24 and 48. The second start is 8 bytes off a 16-byte boundary and the third payload crosses the cache-line boundary at offset 64. Adding 8 bytes after each payload moves the starts to 0, 32 and 64.
Packed 24-byte records start at offsets 0, 24 and 48. The second start is 8 bytes off a 16-byte boundary and the third payload crosses the cache-line boundary at offset 64. Adding 8 bytes after each payload moves the starts to 0, 32 and 64.
The dotted guides mark 16-byte alignment boundaries. The dashed guide at byte 64 also marks the assumed cache-line boundary. Hatched space is padding.

Which boundary matters?

Type alignment concerns the address used for a typed access. For example, Rust places consecutive elements of a native array one type size apart, including any trailing padding. A field inside a record has its own address and alignment requirement. Even with aligned record starts, a byte offset inside the record can leave a field unaligned. For packed feed messages, decode fields from bytes or use an access routine whose contract explicitly permits unaligned addresses. An unaligned Rust reference is invalid even on processors that support some unaligned instructions. The Rust Reference — Type layout, Linux kernel documentation — Unaligned Memory Accesses
Cache-line layout concerns which bytes an operation touches. Assume 64-byte cache lines, with a boundary at the buffer base. The third packed record starts at offset 48, a multiple of 16, yet its payload occupies offsets 48–71 and therefore spans two lines. The third padded record starts at offset 64 and fits within one line. Whether a machine instruction crosses a line depends on the width and address of the actual access. The performance effect also depends on the processor and workload. Padding increases the buffer footprint, so compare the layouts using the access pattern of the actual parser or replay. Intel VTune Profiler User Guide — CPU Metrics Reference
The SelfMadeQuant lesson on arrays, linked lists, stacks and queues works through the index-to-address calculation for contiguous arrays. A public preview is available, and the full lesson requires membership.

Sources

Last updated
  • memory layout
  • alignment
  • padding
  • cache lines
← Back to the glossaryBack to top ↑