| name | memlab-analysis |
| description | Expert skill for JavaScript memory leak detection using Facebook MemLab. Configure MemLab scenarios, execute memory leak detection runs, analyze heap snapshots, identify detached DOM elements, find event listener leaks, and integrate with CI pipelines. |
| allowed-tools | Bash(*) Read Write Edit Glob Grep WebFetch |
| metadata | {"author":"babysitter-sdk","version":"1.0.0","category":"memory-profiling","backlog-id":"SK-017"} |
| graph | {"domains":["domain:software-engineering"],"specializations":["specialization:performance-optimization"],"skillAreas":["skill-area:profiling-memory","skill-area:frontend-performance-testing"],"roles":["role:frontend-engineer","role:backend-engineer"],"topics":["topic:observability-driven-development"]} |
memlab-analysis
You are memlab-analysis - a specialized skill for JavaScript memory leak detection using Facebook's MemLab framework. This skill provides expert capabilities for detecting, analyzing, and fixing memory leaks in web applications.
Overview
This skill enables AI-powered JavaScript memory analysis including:
- Configuring MemLab test scenarios
- Executing automated memory leak detection runs
- Analyzing heap snapshots for memory growth
- Identifying detached DOM elements
- Finding event listener and closure leaks
- Generating actionable MemLab reports
- Integrating with CI/CD pipelines
Prerequisites
- Node.js 16+ (18+ recommended)
- MemLab CLI:
npm install -g memlab
- Chrome/Chromium browser
- Optional: Puppeteer for custom scenarios
Capabilities
1. MemLab Scenario Development
Write comprehensive MemLab test scenarios:
module.exports = {
name: 'user-dashboard-leak-test',
async setup(page) {
await page.goto('https://app.example.com/');
await page.waitForSelector('.login-form');
},
async action(page) {
await page.type('#email', 'test@example.com');
await page.type('#password', 'password123');
await page.click('#login-button');
await page.waitForSelector('.dashboard');
await page.click('[data-testid="analytics-tab"]');
await page.waitForSelector('.analytics-charts');
await page.click('[data-testid="chart-filter"]');
await page.();
},
() {
page.();
page.();
},
() {
(node. === ) ;
(node. < ) ;
;
}
};
2. Advanced Scenario Patterns
Complex scenario configurations:
module.exports = {
name: 'modal-dialog-leak',
url: () => 'https://app.example.com/products',
async setup(page) {
await page.setViewport({ width: 1920, height: 1080 });
await page.evaluate(() => {
window.memlab = { startTime: Date.now() };
});
},
async action(page) {
await page.click('[data-testid="add-product-btn"]');
await page.waitForSelector('.modal-overlay');
await page.type('[name="productName"]', 'Test Product');
await page.type('[name="description"]', 'Test Description');
const input = await page.$('[type="file"]');
input.();
page.();
page.();
page.(, { : });
},
() {
page.( {
.( ());
});
page.();
},
: ,
() {
suspectTypes = [
,
,
,
];
suspectTypes.(node.);
}
};
3. SPA Route Navigation Testing
Test memory leaks during route changes:
module.exports = {
name: 'spa-route-navigation',
async setup(page) {
await page.goto('https://app.example.com/');
await page.waitForNetworkIdle();
},
async action(page) {
const routes = [
'/dashboard',
'/products',
'/orders',
'/settings',
'/analytics'
];
for (const route of routes) {
await page.click(`a[href="${route}"]`);
await page.waitForNetworkIdle();
await page.waitForTimeout(500);
}
},
async back(page) {
await page.click('a[href="/"]');
await page.waitForNetworkIdle();
}
};
4. Event Listener Leak Detection
Detect event listener accumulation:
module.exports = {
name: 'event-listener-leak',
async setup(page) {
await page.goto('https://app.example.com/');
await page.evaluate(() => {
const originalAddEventListener = EventTarget.prototype.addEventListener;
const originalRemoveEventListener = EventTarget.prototype.removeEventListener;
window.__eventListenerCount = 0;
window.__eventListeners = new Map();
EventTarget.prototype.addEventListener = function(type, listener, options) {
window.__eventListenerCount++;
const key = `${this.constructor.name}:${type}`;
window.__eventListeners.set(key, (window..(key) || ) + );
originalAddEventListener.(, type, listener, options);
};
.. = () {
.--;
key = ;
..(key, (..(key) || ) - );
originalRemoveEventListener.(, type, listener, options);
};
});
},
() {
page.();
page.();
page.();
page.(, { : });
},
() {
stats = page.( ({
: .,
: .(.)
}));
.(, stats);
page.();
}
};
5. Running MemLab Analysis
Execute MemLab commands:
memlab run --scenario scenario.js
memlab run --scenario scenario.js --work-dir ./memlab-results
memlab snapshot --scenario scenario.js
memlab find-leaks --work-dir ./memlab-results
memlab analyze ./memlab-results
memlab report --work-dir ./memlab-results --output-dir ./reports
memlab run --scenario scenario.js --headless
memlab run --scenario scenario.js --chromium-binary /path/to/chrome
6. Heap Snapshot Analysis
Analyze heap snapshots for memory issues:
const { takeNodeMinimalHeap, findLeaks } = require('@memlab/api');
async function analyzeHeap() {
const heap = await takeNodeMinimalHeap();
const detachedDOMNodes = heap.nodes.filter(node =>
node.name.startsWith('Detached ') &&
node.type === 'native'
);
const largeObjects = heap.nodes
.filter(node => node.retainedSize > 1024 * 1024)
.sort((a, b) => b.retainedSize - a.retainedSize)
.slice(0, 10);
const closureLeaks = heap.nodes.filter(node =>
node.type === 'closure' &&
node.retainedSize >
);
.();
.(, detachedDOMNodes.);
.(, largeObjects.( ({
: n.,
: n.,
:
})));
.(, closureLeaks.);
}
7. CI/CD Integration
Integrate MemLab into CI pipelines:
name: Memory Leak Check
on:
pull_request:
branches: [main]
jobs:
memlab:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
- name: Install dependencies
run: npm ci
- name: Build application
run: npm run build
- name: Start application
run: npm run start &
env:
PORT: 3000
- name: Wait for
8. Common Leak Pattern Detection
Identify common JavaScript memory leak patterns:
module.exports = {
detectDetachedDOM(node) {
return node.name.startsWith('Detached ') &&
['HTMLDivElement', 'HTMLSpanElement', 'HTMLImageElement']
.some(type => node.name.includes(type));
},
detectEventListenerLeak(node) {
return node.type === 'object' &&
node.name === 'EventListener' &&
node.retainedSize > 1024;
},
detectClosureLeak(node) {
return node.type === 'closure' &&
node.retainedSize > 10240 &&
node.edges.some(edge => edge.name === 'context');
},
detectTimerLeak(node) {
return node.name === 'Timeout' || node. === ;
},
() {
node. === &&
node..(
edge. === && edge.. >
);
},
() {
componentPatterns = [
,
,
];
componentPatterns.( node..(p));
}
};
MCP Server Integration
This skill can leverage the following MCP servers:
| Server | Description | Use Case |
|---|
| playwright-mcp | Browser automation | Custom scenarios |
| clinic.js | Node.js profiling | Alternative memory analysis |
Best Practices
Scenario Design
- Realistic user flows - Model actual user behavior
- Multiple iterations - Repeat actions to amplify leaks
- Clean back state - Ensure proper cleanup verification
- Focused tests - One potential leak source per scenario
Leak Detection
- Filter noise - Ignore known non-leaks
- Size thresholds - Focus on significant leaks
- Retainer paths - Understand why objects are retained
- DOM focus - Detached DOM is the most common leak
CI Integration
- Run on PRs - Catch leaks before merge
- Baseline comparison - Compare against known-good state
- Fail threshold - Set acceptable leak limits
- Artifact retention - Keep heap dumps for analysis
Process Integration
This skill integrates with the following processes:
memory-leak-detection.js - Memory leak detection workflows
memory-profiling-analysis.js - Comprehensive memory analysis
Output Format
When executing operations, provide structured output:
{
"operation": "detect-leaks",
"status": "completed",
"scenario": "dashboard-leak-test",
"results": {
"leaksFound": 3,
"totalLeakedSize": "2.5 MB",
"leaks": [
{
"type": "Detached HTMLDivElement",
"count": 15,
"totalSize": "1.2 MB",
"retainerPath": ["Window", "EventTarget", "handlers", "closure"],
"sourceFile": "dashboard.js:245"
},
Error Handling
Common Issues
| Error | Cause | Resolution |
|---|
Chrome not found | Missing browser | Install Chrome or specify path |
Timeout exceeded | Slow page load | Increase timeout, check network |
OOM in analysis | Large heap | Increase Node.js memory limit |
No leaks found | Scenario too short | Increase iterations, longer actions |
Constraints
- Requires Chrome/Chromium browser
- Heap analysis can be memory-intensive
- False positives possible - manual verification recommended
- Works best with source maps available