CONCEPT Cited by 1 source
JavaScript heap size¶
JavaScript heap size is the memory the browser's JS engine (V8 in Chromium / Edge, SpiderMonkey in Firefox, JavaScriptCore in Safari) allocates for JS objects, closures, and arrays on a page. Distinct from the DOM (concepts/dom-node-count) which is allocated by the layout engine — both live in the tab's process but grow from different sources.
Why it matters¶
- Per-tab ceiling: browsers cap heap at roughly 1-4 GB per renderer process; exceeding it crashes the tab.
- GC pauses scale with heap size: a larger heap means longer stop-the-world pauses during full GC, spiking tail latency on the main thread. This directly affects INP.
- Cross-site cost: on mobile, competing tabs + OS constraints can evict a tab that's using >500 MB of heap.
- OOM manifests as unresponsive page / tab crash — not a graceful degradation path.
Sources of heap growth in rich UIs¶
- Component instances and their state. Each React / Vue / Angular component instance keeps its hooks, closures, refs, and props in the heap. Long lists of components multiply this cost.
- Event handlers and their closures. Every closure retains its capture set — if handlers capture large objects, the objects stay resident.
- Cached / accumulated data. API response caches, scroll buffers, undo histories.
- Large strings / source maps / blob data accumulated by tooling libraries.
Measurement¶
- Chrome DevTools Memory tab — heap snapshots + allocation profiler.
performance.memory.usedJSHeapSize(deprecated but widely supported in Chrome) for RUM-style reporting.- Memory tagging in RUM dashboards: attribute each user session's heap growth to the feature / route it happened on. GitHub's Datadog dashboard tags heap against PR-size buckets (systems/github-pull-requests).
Canonical wiki instance¶
GitHub's Files-changed tab on extreme-tail PRs: JS heap >1 GB (pre-optimization). On the published 10,000-line split-diff benchmark:
- v1: 150-250 MB
- v2: 80-120 MB (~50 % less)
- p95+ virtualized: 10× reduction vs pre-virtualization
The v2 memory win was driven by the React runtime layer (components + state + handlers) shrinking 74 %, despite the DOM only shrinking 10 % — i.e. most of the heap cost was React's component tree, not the DOM itself.
Server-side analogue¶
At the process level, server-side runtimes have the same RSS-vs-
committed-vs-in-use distinction: see
concepts/go-runtime-memory-model for the Go 1.24 regression
case where virtual heap was stable but resident memory spiked.
The same "which metric am I actually reading?" lesson applies —
browsers' performance.memory reports V8's allocated heap, not
necessarily the page's full resident set (renderer-process memory
includes DOM, compositor, images, etc.).
Related¶
- concepts/dom-node-count — the orthogonal cost axis in the same tab process.
- concepts/interaction-to-next-paint — the metric heap pressure degrades (via GC pauses).
- concepts/window-virtualization — the structural fix when list-scaled heap cost is the bottleneck.
- concepts/hot-path — per-interaction code path; heap-cost analysis usually starts here.
- concepts/go-runtime-memory-model — server-side sibling concept for runtime memory accounting.
- systems/github-pull-requests — canonical wiki instance with published numbers.