Skip to content

Commit 5e961a6

Browse files
committed
feat: initial memory debugging skill
1 parent 57e7d51 commit 5e961a6

4 files changed

Lines changed: 123 additions & 0 deletions

File tree

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
---
2+
name: memory-leak-debugging
3+
description: Diagnoses and resolves memory leaks in JavaScript/Node.js applications. Use when a user reports high memory usage, OOM errors, or wants to analyze heapsnapshots or run memory leak detection tools like memlab.
4+
---
5+
6+
# Memory Leak Debugging
7+
8+
This skill provides expert guidance and workflows for finding, diagnosing, and fixing memory leaks in JavaScript and Node.js applications.
9+
10+
## Core Principles
11+
12+
- **Prefer `memlab`:** Do NOT attempt to read raw `.heapsnapshot` files directly, as they are extremely large and will consume too many tokens. Always recommend and use `memlab` to process snapshots and identify leak traces.
13+
- **Isolate the Leak:** Determine if the leak is in the browser (client-side) or Node.js (server-side).
14+
- **Common Culprits:** Look for detached DOM nodes, unhandled closures, global variables, event listeners not being removed, and caches growing unbounded.
15+
16+
## Workflows
17+
18+
### 1. Using Memlab (Recommended)
19+
20+
When users provide `.heapsnapshot` files or want to find a memory leak, use `memlab` to automatically find memory leaks.
21+
22+
- Read [references/memlab.md](references/memlab.md) for how to use `memlab` to analyze existing heapsnapshots or run automated E2E test scenarios to find leaks.
23+
- Do **not** read raw `.heapsnapshot` files using `read_file` or `cat`.
24+
25+
### 2. Identifying Common Leaks
26+
27+
When you have found a leak trace (e.g., via `memlab` output), you must identify the root cause in the code.
28+
29+
- Read [references/common-leaks.md](references/common-leaks.md) for examples of common memory leaks and how to fix them.
30+
31+
### 3. Creating Memlab Scenarios
32+
33+
To help users reproduce and test for leaks automatically, you can create a Memlab scenario file.
34+
35+
- An example template is available at `scripts/memlab-scenario.js`.
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Common Memory Leaks
2+
3+
When analyzing a retainer trace from `memlab`, look for these common patterns in the codebase:
4+
5+
## 1. Detached DOM Nodes
6+
7+
A DOM node is removed from the document tree but is still referenced by a JavaScript variable.
8+
9+
**Fix:** Ensure variables holding DOM references are set to `null` when the node is removed, or limit their scope.
10+
11+
## 2. Uncleared Event Listeners
12+
13+
Event listeners attached to global objects (like `window` or `document`) or long-living objects prevent garbage collection of the objects referenced in their callbacks.
14+
15+
**Fix:** Always call `removeEventListener` when a component unmounts or the listener is no longer needed.
16+
17+
## 3. Unintentional Global Variables
18+
19+
Variables declared without `var`, `let`, or `const` (in non-strict mode) or explicitly attached to `window` remain in memory forever.
20+
21+
**Fix:** Use strict mode, properly declare variables, and avoid global state.
22+
23+
## 4. Closures
24+
25+
Closures can unintentionally keep references to large objects in their outer scope.
26+
27+
**Fix:** Nullify large objects when they are no longer needed, or refactor the closure to not capture unnecessary variables.
28+
29+
## 5. Unbounded Caches or Arrays
30+
31+
Data structures used for caching (like objects, Arrays, or Maps) that grow without limits.
32+
33+
**Fix:** Implement caching limits, use LRU caches, or use `WeakMap`/`WeakSet` for data associated with object lifecycles.
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Using Memlab
2+
3+
[Memlab](https://facebook.github.io/memlab/) is an E2E testing and analysis framework for finding JavaScript memory leaks.
4+
5+
## Important Rule
6+
7+
**NEVER read raw `.heapsnapshot` files directly.** They are too large and will exceed context limits. Use `memlab` commands to analyze them instead.
8+
9+
## Analyzing Existing Snapshots
10+
11+
If the user provides 3 snapshots (baseline, target, final), you can use `memlab` to find leaks:
12+
13+
```bash
14+
npx memlab find-leaks --baseline <path-to-baseline> --target <path-to-target> --final <path-to-final>
15+
```
16+
17+
You can also parse a single snapshot to find the largest objects:
18+
19+
```bash
20+
npx memlab analyze snapshot --snapshot <path-to-snapshot>
21+
```
22+
23+
## Running Automated Scenarios
24+
25+
Memlab can automatically open a browser, interact with a page, take snapshots, and find leaks.
26+
You need a scenario file (e.g., `scenario.js`).
27+
28+
```bash
29+
npx memlab run --scenario <path-to-scenario.js>
30+
```
31+
32+
Memlab will output the retainer traces for identified leaks. Use these traces to guide your search in the codebase.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Memlab Scenario Template
2+
module.exports = {
3+
// Required: The URL to load
4+
url: () => 'http://localhost:3000',
5+
6+
// Required: Action to trigger the memory leak
7+
action: async (page) => {
8+
// Example: Click a button that causes a leak
9+
await page.click('#leak-button');
10+
// Wait for any animations or network requests to settle
11+
await new Promise(resolve => setTimeout(resolve, 1000));
12+
},
13+
14+
// Required: Action to revert to the baseline state
15+
back: async (page) => {
16+
// Example: Click a back button or close a modal
17+
await page.click('#back-button');
18+
await new Promise(resolve => setTimeout(resolve, 1000));
19+
},
20+
21+
// Optional: Function to run before taking the baseline snapshot
22+
// setup: async (page) => { ... },
23+
};

0 commit comments

Comments
 (0)