Skip to content
memory-leak-detection logo

Memory Leak Detection

memory-leak-detection

Detect and fix memory leaks using heap snapshots, memory profiling, and leak detection tools. Use when investigating memory growth, OOM errors, or optimizing memory usage.

SKILL.md

Full skill instructions

Memory Leak Detection

Overview

Identify and fix memory leaks to prevent out-of-memory crashes and optimize application performance.

When to Use

  • Memory usage growing over time
  • Out of memory (OOM) errors
  • Performance degradation
  • Container restarts
  • High memory consumption

Implementation Examples

1. Node.js Heap Snapshots

import v8 from 'v8';
import fs from 'fs';

class MemoryProfiler {
  takeSnapshot(filename: string): void {
    const snapshot = v8.writeHeapSnapshot(filename);
    console.log(`Heap snapshot saved to ${snapshot}`);
  }

  getMemoryUsage(): NodeJS.MemoryUsage {
    return process.memoryUsage();
  }

  formatMemory(bytes: number): string {
    return `${(bytes / 1024 / 1024).toFixed(2)} MB`;
  }

  printMemoryUsage(): void {
    const usage = this.getMemoryUsage();

    console.log('Memory Usage:');
    console.log(`  RSS: ${this.formatMemory(usage.rss)}`);
    console.log(`  Heap Total: ${this.formatMemory(usage.heapTotal)}`);
    console.log(`  Heap Used: ${this.formatMemory(usage.heapUsed)}`);
    console.log(`  External: ${this.formatMemory(usage.external)}`);
  }

  monitorMemory(interval: number = 5000): void {
    setInterval(() => {
      this.printMemoryUsage();
    }, interval);
  }
}

// Usage
const profiler = new MemoryProfiler();

// Take initial snapshot
profiler.takeSnapshot('./​heap-before.heapsnapshot');

// Run application
await runApp();

// Take final snapshot
profiler.takeSnapshot('./​heap-after.heapsnapshot');

// Compare in Chrome DevTools to find leaks

2. Memory Leak Detection Middleware

class LeakDetector {
  private samples: number[] = [];
  private maxSamples = 10;
  private threshold = 1.5; // 50% growth

  checkForLeak(): boolean {
    const usage = process.memoryUsage();
    this.samples.push(usage.heapUsed);

    if (this.samples.length > this.maxSamples) {
      this.samples.shift();
    }

    if (this.samples.length < this.maxSamples) {
      return false;
    }

    const first = this.samples[0];
    const last = this.samples[this.samples.length - 1];
    const growth = last / first;

    return growth > this.threshold;
  }

  startMonitoring(interval: number = 10000): void {
    setInterval(() => {
      if (this.checkForLeak()) {
        console.warn('⚠️  Potential memory leak detected!');
        console.warn('Memory samples:', this.samples.map(s =>
          `${(s / 1024 / 1024).toFixed(2)} MB`
        ));
      }
    }, interval);
  }
}

// Usage
const detector = new LeakDetector();
detector.startMonitoring();

3. Common Memory Leak Patterns

// BAD: Event listener leak
class BadComponent {
  constructor() {
    window.addEventListener('resize', this.handleResize);
  }

  handleResize = () => {
    // Handler logic
  }

  // Missing cleanup!
}

// GOOD: Proper cleanup
class GoodComponent {
  constructor() {
    window.addEventListener('resize', this.handleResize);
  }

  handleResize = () => {
    // Handler logic
  }

  destroy() {
    window.removeEventListener('resize', this.handleResize);
  }
}

// BAD: Timer leak
function badFunction() {
  setInterval(() => {
    doSomething();
  }, 1000);
  // Interval never cleared!
}

// GOOD: Clear timer
function goodFunction() {
  const intervalId = setInterval(() => {
    doSomething();
  }, 1000);

  return () => clearInterval(intervalId);
}

// BAD: Closure leak
function createClosure() {
  const largeData = new Array(1000000).fill('data');

  return function() {
    // largeData kept in memory even if unused
    console.log('closure');
  };
}

// GOOD: Don't capture unnecessary data
function createClosure() {
  const needed = 'small data';

  return function() {
    console.log(needed);
  };
}

// BAD: Global variable accumulation
let cache = [];

function addToCache(item: any) {
  cache.push(item);
  // Cache grows indefinitely!
}

// GOOD: Bounded cache
class BoundedCache {
  private cache: any[] = [];
  private maxSize = 1000;

  add(item: any) {
    this.cache.push(item);
    if (this.cache.length > this.maxSize) {
      this.cache.shift();
    }
  }
}

4. Python Memory Profiling

import tracemalloc
from typing import List, Tuple

class MemoryProfiler:
    def __init__(self):
        self.snapshots: List = []

    def start(self):
        """Start tracking memory allocations."""
        tracemalloc.start()

    def take_snapshot(self):
        """Take a memory snapshot."""
        snapshot = tracemalloc.take_snapshot()
        self.snapshots.append(snapshot)
        return snapshot

    def compare_snapshots(
        self,
        snapshot1_idx: int,
        snapshot2_idx: int,
        top_n: int = 10
    ):
        """Compare two snapshots."""
        snapshot1 = self.snapshots[snapshot1_idx]
        snapshot2 = self.snapshots[snapshot2_idx]

        stats = snapshot2.compare_to(snapshot1, 'lineno')

        print(f"\nTop {top_n} memory differences:")
        for stat in stats[:top_n]:
            print(f"{stat.size_diff / 1024:.1f} KB: {stat.traceback}")

    def get_top_allocations(self, snapshot_idx: int = -1, top_n: int = 10):
        """Get top memory allocations."""
        snapshot = self.snapshots[snapshot_idx]
        stats = snapshot.statistics('lineno')

        print(f"\nTop {top_n} memory allocations:")
        for stat in stats[:top_n]:
            print(f"{stat.size / 1024:.1f} KB: {stat.traceback}")

    def stop(self):
        """Stop tracking."""
        tracemalloc.stop()


# Usage
profiler = MemoryProfiler()
profiler.start()

# Take initial snapshot
profiler.take_snapshot()

# Run code
data = [i for i in range(1000000)]  # Allocate memory

# Take another snapshot
profiler.take_snapshot()

# Compare
profiler.compare_snapshots(0, 1)

profiler.stop()

5. WeakMap/​WeakRef for Cache

class WeakCache<K extends object, V> {
  private cache = new WeakMap<K, V>();

  set(key: K, value: V): void {
    this.cache.set(key, value);
  }

  get(key: K): V | undefined {
    return this.cache.get(key);
  }

  has(key: K): boolean {
    return this.cache.has(key);
  }

  delete(key: K): void {
    this.cache.delete(key);
  }
}

// Objects can be garbage collected even if in cache
const cache = new WeakCache<object, string>();
let obj = { id: 1 };

cache.set(obj, 'data');

// When obj is no longer referenced, it can be GC'd
obj = null as any;

6. Memory Monitoring in Production

class MemoryMonitor {
  private alerts: Array<(usage: NodeJS.MemoryUsage) => void> = [];

  startMonitoring(options: {
    interval?: number;
    heapThreshold?: number;
    rssThreshold?: number;
  } = {}): void {
    const {
      interval = 60000,
      heapThreshold = 0.9,
      rssThreshold = 0.95
    } = options;

    setInterval(() => {
      const usage = process.memoryUsage();
      const heapUsedPercent = usage.heapUsed / usage.heapTotal;

      if (heapUsedPercent > heapThreshold) {
        console.warn(
          `⚠️  High heap usage: ${(heapUsedPercent * 100).toFixed(2)}%`
        );

        this.alerts.forEach(fn => fn(usage));

        // Force GC if available
        if (global.gc) {
          console.log('Forcing garbage collection...');
          global.gc();
        }
      }
    }, interval);
  }

  onAlert(callback: (usage: NodeJS.MemoryUsage) => void): void {
    this.alerts.push(callback);
  }
}

// Usage
const monitor = new MemoryMonitor();

monitor.onAlert((usage) => {
  // Send alert to monitoring service
  console.error('Memory alert triggered:', usage);
});

monitor.startMonitoring({
  interval: 30000,
  heapThreshold: 0.85
});

Best Practices

✅ DO

  • Remove event listeners when done
  • Clear timers and intervals
  • Use WeakMap/​WeakRef for caches
  • Limit cache sizes
  • Monitor memory in production
  • Profile regularly
  • Clean up after tests

❌ DON'T

  • Create circular references
  • Hold references to large objects unnecessarily
  • Forget to clean up resources
  • Ignore memory growth
  • Skip WeakMap for object caches

Tools

  • Node.js: Chrome DevTools, heapdump, memwatch-next
  • Python: tracemalloc, memory_profiler, pympler
  • Browsers: Chrome DevTools Memory Profiler
  • Production: New Relic, DataDog APM

Resources

More skills from majiayu000

xiaohongshu logo
majiayu000/claude-arsenal

xiaohongshu

xiaohongshu

286 148
View
agent-task-conductor logo
majiayu000/claude-skill-registry

agent-task-conductor

Conduct multi-agent task orchestration and workflow coordination.

663 1
View
conductor-setup logo
majiayu000/claude-skill-registry

conductor-setup

Initialize project with Conductor artifacts (product definition,

663 1
View
animation-designer logo
majiayu000/claude-skill-registry

animation-designer

Expert in web animations, transitions, and motion design using Framer Motion and CSS

663 1
View
diagramming logo
majiayu000/claude-skill-registry

diagramming

Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...

663 1
View
h3-pg logo
majiayu000/claude-skill-registry-data

h3-pg

PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.

23 1
View
conductor-development logo
majiayu000/claude-skill-registry

conductor-development

Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...

663 1
View
conductor-status logo
majiayu000/claude-skill-registry

conductor-status

Display project status, active tracks, and next actions

663 1
View
dockerization logo
majiayu000/claude-skill-registry

dockerization

Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.

663 1
View

Popular AI tools

Kaiber logo
Video

Kaiber

Generate, edit, and beat-sync AI video with leading models in one workspace.

Paid
View
Vimcal logo
Productivity

Vimcal

The world's fastest calendar for remote work

Free
View

Transform Your Design with AI Designer by ImgCreator.ai

Freemium
View
Akool AI logo
Content & writing

Akool AI

Revolutionizing Video Production with AI-Powered Creativity

Paid
View

Extend an image past the frame and let AI fill the new aspect ratio.

Freemium
View
StarByFace logo
Security

StarByFace

Discover your celebrity doppelgänger with StarByFace!

Free
View
C

ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.

Freemium
View
Opus Clip logo
Coding & apps

Opus Clip

Opus.ai: Revolutionize Your Web Experience

Free
View