Documentation

How to use HeapScope

Learn how to analyze Chrome heap snapshots, interpret the data, and identify memory leaks in your JavaScript applications.

Getting Started

Step 1: Get Your Heap Snapshot

  1. Open Chrome DevTools (F12 or Cmd+Option+I)
  2. Go to the Memory tab
  3. Select "Heap snapshot" as your profiling type
  4. Click "Take snapshot" after your app has been running for a while (so leaks have time to accumulate)
  5. Download the resulting .heaptimeline file

Step 2: Upload to HeapScope

Go to the Dashboard, drag your snapshot file onto the drop zone (or click to browse), and HeapScope will analyze it instantly in your browser โ€” no upload, no waiting.

๐Ÿ’ก Your data never leaves your computer. Analysis happens 100% client-side.

Understanding Each Tab

Leak Detection

What you're looking at: Suspected memory leak candidates, ranked by severity. HeapScope uses heuristics to detect patterns that commonly indicate leaks.

Severity levels

  • High Immediate risk; investigate first
  • Med Potential issue; worth reviewing
  • Low Minor patterns; observe in production

Common leak types

  • Detached DOM nodes โ€” Elements removed from the DOM but still held in memory
  • EventEmitter / Subscription accumulation โ€” Event listeners or RxJS subscriptions never removed
  • Promise accumulation โ€” Unresolved or chained promises piling up
  • Closure retention โ€” References held in closure scopes
  • Array/String buildup โ€” Collections that grow unbounded
  • Map/Set growth โ€” Collections used as caches without size limits
  • Compiled code bloat โ€” Excessive eval() or dynamically generated functions

How to act on leak results

  1. Start with High severity items โ€” these are almost always real problems
  2. Expand each leak card to read the Issue description and Recommendation
  3. Check the Affected types section to see which constructors are involved
  4. Use the Detached Nodes tab to trace retainer chains back to your code
  5. Verify by taking a second snapshot after the suspected leak action and comparing

โš ๏ธ These are heuristic detections. Not all flagged items are actual leaks โ€” always verify by reviewing the code paths.

Growth Over Time

What you're looking at: Object allocation trends over time. Two charts show allocation rate and cumulative object count.

Object Allocation Rate

A bar chart showing how many new objects were created in each time window.

  • Orange spikes โ€” Normal allocation
  • Red spikes โ€” Large allocation burst (may indicate a leak)

Cumulative Objects Allocated

A line chart tracking total object count over time.

  • Steady climb โ€” Objects accumulating, likely not being garbage collected
  • Plateau โ€” Healthy; objects are being freed and recreated
  • Downward drops โ€” GC events reclaiming objects (see GC Health tab for details)

How to use this data

If you see a steady climb in cumulative objects with no downward drops, that's a strong leak signal. Cross-reference with the GC Health tab to confirm whether garbage collection is happening at all.

By Script

What you're looking at: Memory attributed to each JavaScript source file, based on call stacks captured during allocation.

How to read it

  • Script โ€” Source file name (if resolvable) or Script ID
  • Objects โ€” Count of objects created by this script
  • Total retained โ€” Memory still held (not garbage collected)
  • Avg size โ€” Average bytes per object from this script
  • Sample objects โ€” Examples of object types this script creates

How to use this data

If a script shows high "Total retained" with many objects, investigate why those objects aren't being freed. This often points to a specific library, component, or module that's holding references. Look for third-party libraries (analytics, widgets, SDKs) that may not clean up after themselves.

๐Ÿ’ก If a script shows high "Total retained" with many objects, investigate why those objects aren't being freed.

Large Objects

What you're looking at: The top 20 object types by total retained heap size.

Metrics

  • Constructor โ€” Type name (e.g., Array, HTMLDivElement)
  • Count โ€” How many instances of this type exist
  • Total size โ€” Combined memory for all instances
  • Avg size โ€” Memory per instance

How to use this data

High object counts (>10k) or large average sizes may indicate bloat or improper data structures. Compare with the Type Analysis charts to see if a type has many small instances (possible accumulation) or few large instances (possible buffer leak).

โš ๏ธ High object counts (>10k) or large average sizes may indicate bloat or improper data structures.

Type Analysis

What you're looking at: Two visualizations showing heap composition: memory distribution by type (doughnut) and object count by type (horizontal bar).

Memory by Type (Doughnut)

Shows which object types consume the most total heap memory. Helps identify memory hogs.

Object Count by Type (Bar)

Shows which types have the most instances. High counts may indicate accumulation or caching issues.

How to use this data

Compare both charts: if a type has many instances but little memory (like small strings), vs. few instances but lots of memory (like large buffers), you'll see different culprits. A type that dominates both charts is your primary target for investigation.

๐Ÿ’ก Compare both charts: if a type has many instances but little memory (like small strings), vs. few instances but lots of memory (like large buffers), you'll see different culprits.

Detached Nodes

What you're looking at: DOM elements that have been removed from the document but are still held in memory by JavaScript references.

Why detached nodes matter

When you remove an element from the DOM, the browser normally garbage collects it. But if your code holds a reference to it (e.g., in a closure, global, or event listener), the browser can't free it โ€” and it stays in memory indefinitely.

Reading the list

  • ID โ€” Internal heap object ID
  • Type โ€” DOM node type (e.g., HTMLDivElement)
  • Direct Retainers โ€” Objects that directly reference this node
  • Retainer Chain โ€” The full path from a GC root to this node, showing why it's still alive

How to use retainer chains

The retainer chain traces backwards from the leaked node toward a GC root. Each arrow shows which object holds a reference, and via what property. Follow the chain to find the root cause โ€” often a global store, event emitter, or closure that's keeping the entire subtree alive. The object at the end of the chain (marked [root]) is your cleanup target.

๐Ÿ’ก Click on a detached node to expand its retainers and trace the reference chain โ€” this tells you what to fix in your code.

Size Distribution

What you're looking at: How objects are distributed across size buckets, from tiny (< 64 bytes) to huge (> 100 KB).

The two charts

  • Objects by Size Bucket โ€” How many objects fall into each size range
  • Memory by Size Bucket โ€” Total memory consumed in each size range

How to interpret the data

  • Mostly tiny objects โ€” Normal for most apps; indicates many small primitives and references
  • Many medium/large objects โ€” May indicate large arrays, buffers, or cached data structures
  • Huge objects dominating memory โ€” Likely leaked buffers, image data, or large string caches
  • Disproportionate memory in small buckets โ€” Object overhead bloat; many wrapper objects around small values

How to use this data

If the Memory chart is dominated by huge objects but the Count chart shows few of them, you have a "few big leaks" problem (e.g., unclosed WebSockets holding large buffers). If both charts show dominance in the same bucket, you have a "many small leaks" problem (e.g., accumulating event listeners or state objects).

GC Health

What you're looking at: Whether garbage collection is happening during your recording, and how effective it is at reclaiming objects.

How GC detection works

HeapScope detects GC events by looking for decreases in the cumulative object ID between timeline samples. When the browser garbage collects objects, the next sample's lastId drops because freed IDs are reused.

The stats strip

  • GC Health โ€” "GC active" means collections were detected; "No GC detected" is a strong leak signal
  • GC Events โ€” Number of collections during the recording period
  • Avg reclaimed โ€” Average objects freed per collection
  • Leak signal โ€” "Strong" when no GC happens (everything accumulates); "Moderate" when GC is active but may not be keeping up

The chart

The cumulative objects line with red dots marking GC events. A healthy app shows steady growth with periodic drops. A leaking app shows a smooth upward curve with no drops.

How to use this data

  • No GC events + climbing cumulative โ€” Strong leak signal. Objects are being created but never freed.
  • GC events but cumulative still climbs โ€” GC is working but can't keep up. New objects are being created faster than old ones are freed.
  • GC events + plateauing cumulative โ€” Healthy. Objects are being created and freed at a balanced rate.
  • Frequent GC with small reclaim โ€” Possible churn; many short-lived objects causing GC pressure.

โš ๏ธ GC inference is based on object ID drops, not direct GC pause measurement. It may miss minor GCs that don't reuse IDs immediately.

The Stats Strip

At the top of Leak Detection, four cards summarize your heap:

Total heap size

Your app's current memory footprint. Benchmarks depend on your app, but >200 MB is usually a warning sign.

Suspected leaks

Count of heuristic detections. Zero is ideal; high counts warrant investigation.

Detached DOM nodes

Removed elements still in memory. Any count >0 is suspicious; >100 is a likely leak.

Timeline samples

Allocation snapshots captured during recording. More samples = more detail on growth patterns.

Workflow: Detecting Memory Issues

Step 1: Take a baseline snapshot

Open your app, let it settle, then take a heap snapshot. Upload to HeapScope and note the Total heap size and Suspected leaks count. This is your baseline.

Step 2: Perform a suspect action

Do the action you suspect leaks memory: open a modal, navigate to a page, trigger a data fetch, or interact with a complex component. Then take a second snapshot.

Step 3: Compare and investigate

Upload the second snapshot. Look for:

  • New leak detections that weren't in the baseline
  • Increased counts in Detached Nodes
  • Growth in specific types under Type Analysis
  • New high-retention scripts in By Script

Step 4: Trace the root cause

For the most suspicious leak:

  1. Go to Leak Detection and expand the highest-severity leak
  2. Read the recommendation โ€” it suggests the fix pattern
  3. If detached DOM nodes are involved, go to Detached Nodes and expand the retainer chain
  4. Follow the chain from the leaked node back to the root โ€” the last object in the chain is what you need to clean up
  5. Check GC Health โ€” if no GC is happening, the leak is continuous and severe

Step 5: Fix and verify

Apply the fix (remove listeners, clear caches, unsubscribe, etc.), then repeat Steps 1-2. The leak should disappear or significantly reduce. Use Size Distribution to confirm the shape of the heap has changed โ€” the problematic bucket should shrink.

Quick Tips

๐Ÿ’พ Best practices

Take snapshots after your app has run for several minutes โ€” this gives leaks time to accumulate and become visible.

๐Ÿ” Investigating leaks

Start with Leak Detection โ†’ click a flagged leak โ†’ review the "Source" and "Retainers" to see where the reference is held in your code.

๐Ÿ“Š Comparing snapshots

Take a snapshot, perform an action (e.g., open/close a modal), take another snapshot. Compare results to see what that action leaked.

๐ŸŽฏ Common culprits

Event listeners (remove with removeEventListener), closures (avoid capturing large objects), and timers (clear with clearInterval).

๐Ÿ•ต๏ธ Using retainer chains

The retainer chain traces from a leaked object back to a GC root. The object at the end of the chain (marked [root]) is your cleanup target โ€” fix that, and everything upstream gets freed.

๐Ÿ“‰ GC Health as a leak signal

If GC Health shows "No GC detected" and the cumulative chart is a smooth upward line, you have a severe leak. If GC is active but the line still climbs, GC can't keep up โ€” you're allocating faster than collecting.

Ready to analyze?

Head to the dashboard and upload your first heap snapshot.

Open dashboard