What is a contiguous memory layout?

A contiguous memory layout stores related values in adjacent addresses as one dense block — the way HNSW should hold vectors and neighbor-ID lists — so scans and SIMD loads hit consecutive cache lines instead of chasing per-node heap pointers.
Created: Updated: 4 min read

A contiguous memory layout stores a sequence of related values in adjacent addresses with no gaps of unrelated heap objects between them — one dense block you can index by offset — so scanning or SIMD-processing that sequence walks straight through cache lines instead of chasing pointers across the heap.

What does “contiguous” mean compared with a pointer-linked layout?

In a contiguous layout, item i+1 begins at a fixed stride after item i: vector bytes packed in one arena, neighbor IDs in one array, node records in one table. Given a base pointer and an index, the address is base + index × stride. In a pointer-linked layout, each node heap-allocates its own neighbor buffer or vector copy, and the only way to reach the next piece is to follow a pointer that may land anywhere in the address space. Contiguous layouts trade some flexibility (growing one node’s list may require slab tricks or relocation) for spatial locality, simpler serialization, and cheaper address arithmetic. Linked layouts grow easily node by node but turn every hop into a potential TLB and cache miss even before the algorithmic randomness of graph search is considered.

HNSW performance depends on applying contiguity where the CPU streams data, while accepting that graph topology itself is not a contiguous walk through node IDs.

Which parts of an HNSW index should be contiguous?

Vectors belong in one contiguous arena (or a small number of large slabs) so distance kernels can issue sequential SIMD loads. Neighbor ID lists should be dense arrays — either fixed-capacity slots per node inside a big slab or offsets into a shared edge arena — so scanning M neighbors touches consecutive IDs. Compact node metadata tables work the same way. What cannot be made contiguous is the sequence of nodes visited during search: neighbor 3 of node 10 may be node 905321, anywhere in the ID space. Contiguity removes avoidable scattering inside each node’s payload; it does not make the graph’s logical edges sequential. Production in-memory indexes, including layouts behind systems like Weaviate, lean on large contiguous vector and graph buffers for exactly this split: dense storage, irregular traversal.

Contiguity also unlocks hardware helpers that scattered allocations never see.

How does a contiguous layout interact with prefetching, huge pages, and alignment?

Hardware prefetchers recognize sequential and strided streams through a dense arena; they rarely help a chain of separately malloc’d neighbor buffers. Huge pages map large contiguous virtual regions efficiently; a forest of tiny allocations cannot be promoted as effectively. Alignment is easier to guarantee when you control one base address and a fixed stride for every vector. Contiguous slabs also mmap cleanly: a file region maps to one search-ready arena if the on-disk layout matches. The cost is allocator discipline — reserve capacity, use arenas, avoid per-edge malloc — and sometimes copying when a neighbor list must grow beyond its slot. That cost is paid at build time so queries can run against predictable memory.

Fragmented layouts are a common reason two HNSW implementations with the same algorithm disagree on latency.

What goes wrong when an HNSW implementation abandons contiguity?

Per-node heap allocations for vectors or edges multiply pointer chasing on top of graph chasing, balloon allocator overhead, and make RSS far larger than the logical bytes-per-vector math suggests. Serialization becomes a graph walk of pointers instead of a blunt write of arrays. Warm-up takes longer because cold misses scatter across the heap. Under concurrency, allocators contend while searches pay extra latency. If profiles show abundant TLB and cache misses inside neighbor-list access even for a single node’s list scan — not merely between nodes — suspect non-contiguous edge storage. Restoring arena allocation and fixed strides usually wins more than micro-tuning the distance kernel on a fragmented graph.

A contiguous memory layout packs related HNSW bytes into dense addressable blocks so vectors and neighbor lists stream efficiently, even though search still jumps irregularly between node IDs. From here, the array and structure-of-arrays pages describe how those blocks are organized, prefetching and huge pages explain hardware payoffs, allocator overhead covers the tax of scattered mallocs, and the chapter on laying out HNSW in memory shows concrete arena designs.