Why Large Holey Arrays in V8 Switch to Dictionary Mode and Save Memory
The article explains how V8 decides to convert a large holey JavaScript array into a dictionary (slow) representation, showing code examples, heap snapshots, and the internal algorithm that reduces memory usage when the array exceeds certain thresholds.
While debugging a memory issue, two similar JavaScript snippets were compared: one creates an array of length 99999 and assigns undefined to index 99998, the other assigns to index 99999. Heap snapshots taken with node --inspect-brk reveal that the second snippet consumes noticeably less memory.
const a = new Array(99999);
a[99998] = undefined; const b = new Array(99999);
b[99999] = undefined;V8 distinguishes between fast and slow array modes. Fast arrays store elements contiguously, while slow arrays use a hash table. Arrays are also classified as Packed (no holes) or Holey (with uninitialized slots). Large holey arrays waste memory, so V8 optimizes them by converting to a dictionary (slow) representation.
Debugging with v8‑debug (installable via jsvu) shows the first array as a FixedArray and the second as a Dictionary. The conversion decision occurs in the V8 call stack:
Object::SetProperty
> Object::AddDataProperty
> JSObject::AddDataElement
> ShouldConvertToSlowElementsThe ShouldConvertToSlowElements function checks the index being set. If the index is less than the current capacity (e.g., 99998 < 99999), it returns false and no conversion happens. When the index equals 99999, it exceeds the original FixedArray capacity, triggering an expansion to a new capacity calculated as old + old/2 + 16 (about 150 000 slots).
After expansion, V8 calls GetFastElementsUsage to count non‑hole elements, multiplies this count by kPreferFastElementsSizeFactor (value 3) and kEntrySize (value 2), and compares the product to the new capacity. In the second snippet, the non‑hole element count is zero, so the product is zero, which is far less than the new capacity, causing the array to be converted to a slow (dictionary) mode that stores data more compactly.
Thus, the large holey array in the second code fragment becomes a dictionary, dramatically reducing its memory footprint.
Node Underground
No language is immortal—Node.js isn’t either—but thoughtful reflection is priceless. This underground community for Node.js enthusiasts was started by Taobao’s Front‑End Team (FED) to share our original insights and viewpoints from working with Node.js. Follow us. BTW, we’re hiring.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
