Debugging Javascript Memory Leaks


    Let’s dive into debugging memory leaks step-by-step using tools like Chrome DevTools and best practices for Angular. We’ll focus on identifying and fixing issues effectively.


1. Understanding the Tools

Browser DevTools:

  • Performance Tab: Monitor memory usage over time.
  • Memory Tab: Analyze heap snapshots and memory retention.
  • Console: Observe memory usage using the window.performance.memory object (not in all browsers).

Augury Extension:

  • Provides Angular-specific insights such as component hierarchies and bindings.
  • Can highlight improper use of change detection or subscriptions.

RxJS Spy:

  • Helps track Observables and their subscriptions in real time.

2. Step-by-Step Debugging

Step 1: Record Memory Usage

Use the Performance Tab in Chrome DevTools:

  1. Open DevTools (Ctrl + Shift + I or F12).
  2. Go to the Performance tab.
  3. Click Record and interact with your application (e.g., navigate between components).
  4. Stop recording and review:
    • Look for steady memory increases after repeated actions.
    • Identify JS Heap Size growth that doesn’t stabilize.

Step 2: Analyze Heap Snapshots

Heap snapshots help detect unreachable objects or objects still referenced unexpectedly:

  1. Open the Memory tab in DevTools.
  2. Take a Heap Snapshot:
    • Perform a task in the application (e.g., navigate or interact).
    • Take a snapshot.
    • Perform the same task again and take another snapshot.
  3. Compare snapshots:
    • Look for objects that persist after the component is destroyed.

Step 3: Use Allocation Timeline

  • Open the Memory tab and choose Allocation Instrumentation on Timeline.
  • Record your app's actions and stop.
  • Analyze retained memory for signs of lingering objects.

Step 4: Track Detached Elements

If DOM elements aren’t garbage collected:

  1. Use the Console command:
    getEventListeners(document);
  2. Check for unexpected listeners.

3. Debugging Angular-Specific Issues

Issue 1: Observable Subscriptions

Look for unsubscribed Observables:

  1. Use the Memory tab to check for retained subscription objects.
  2. Use RxJS Spy to track live Observables:

    import * as rxjsSpy from '@rxjs-spy/core';
    const spy = rxjsSpy.create();

Fix: Use AsyncPipe or takeUntil as previously mentioned.


Issue 2: Event Listeners

  1. Check with getEventListeners(targetElement) to list active listeners.
  2. Verify in heap snapshots that event listeners are removed when components are destroyed.

Fix: Always remove listeners in ngOnDestroy.


Issue 3: DOM Elements

Detached DOM nodes occur when elements are removed from the DOM but retained in memory:

  • Use the Console command:

    const detachedNodes = performance.getEntriesByType('node');
    console.log(detachedNodes);

Fix: Ensure elements aren’t referenced after removal.


4. Example Debugging Workflow

Scenario:

An Angular app is showing increasing memory usage when navigating between components.

Step-by-Step Solution:

  1. Open Chrome DevTools and go to the Performance tab.
  2. Record a session where you:
    • Navigate to a component.
    • Navigate away and back several times.
  3. Stop recording and observe the JS Heap Size.
  4. Open the Memory tab, take heap snapshots at key points:
    • Before navigation.
    • After navigation.
    • After navigating back and forth multiple times.
  5. Look for retained objects in the snapshot comparison:
    • Components that should have been destroyed.
    • Large data structures retained (e.g., subscription objects, DOM elements).

Common Fixes:

  • Ensure Observables in the component are unsubscribed in ngOnDestroy.
  • Use async pipes instead of manual subscriptions.
  • Check for global variables or dangling DOM references.

5. Tools and Commands Recap

ToolUse Case
Chrome DevToolsRecord memory usage, analyze heap snapshots, track leaks.
AuguryVisualize Angular component tree and change detection.
RxJS SpyMonitor Observables and subscriptions in real time.
Console CommandsDetect event listeners or detached DOM elements.

Comments

Popular posts from this blog

Memory Leaks in Javascripts

Apache Jackrabbit FileVault (VLT)