---
id: daily-memory-leak-audit
name: "memory-leak-audit"
url: https://skills.yangsir.net/skill/daily-memory-leak-audit
author: microsoft
domain: ai-productivity-automation
tags: ["ai-engineering", "prompt-engineering", "automation", "ai-agents"]
install_count: 3200
rating: 4.40 (20 reviews)
github: https://github.com/microsoft/vscode
---

# memory-leak-audit

> memory-leak-audit，AI Agent Skill，提升工作效率和自动化能力

**Stats**: 3,200 installs · 4.4/5 (20 reviews)

## Before / After 对比

### 内存泄漏检测与修复

**Before**:

应用运行数小时后内存占用持续增长，手动排查需要逐个检查事件监听器和DOM引用，定位困难且容易遗漏。

**After**:

AI自动识别常见内存泄漏模式，精准定位未清理的监听器和DOM引用，提供具体修复方案，预防性检查避免新问题。

| Metric | Before | After | Change |
|---|---|---|---|
| 问题定位时间 | 16小时 | 1小时 | -93.8% |
| 内存泄漏复发率 | 40% | 5% | -87.5% |

## Readme

# memory-leak-audit

# Memory Leak Audit

The #1 bug category in VS Code. This skill encodes the patterns that prevent and fix leaks.

## When to Use

- Reviewing code that registers event listeners or DOM handlers

- Fixing reported memory leaks (listener counts growing over time)

- Creating objects in methods that are called repeatedly

- Working with model lifecycle events (onWillDispose, onDidClose)

- Adding event subscriptions in constructors or setup methods

## Audit Checklist

Work through each check in order. A single missed pattern can cause thousands of leaked objects.

### Step 1: DOM Event Listeners

**Rule**: Never use raw `.onload`, `.onclick`, or `addEventListener()` directly. Always use `addDisposableListener()`.

```
// BAD — leaks a listener every call
this.iconElement.onload = () => { ... };

// GOOD — tracked and disposable
this._register(addDisposableListener(this.iconElement, 'load', () => { ... }));

```

**Validated by**: PR #280566 — Extension icon widget leaked 185 listeners after 37 toggles.

### Step 2: One-Time Events

**Rule**: Use `Event.once()` for events that should only fire once (lifecycle events, close events, first-change events).

```
// BAD — listener stays registered forever after first fire
model.onDidDispose(() => store.dispose());

// GOOD — auto-removes after first invocation
Event.once(model.onDidDispose)(() => store.dispose());

```

**Validated by**: PRs #285657, #285661 — Terminal lifecycle hacks replaced with `Event.once()`.

### Step 3: Repeated Method Calls

**Rule**: Objects created in methods called multiple times must NOT be registered to the class `this._register()`. Use `MutableDisposable` or return `IDisposable` to the caller.

```
// BAD — every call adds another listener to the class store
startSearch() {
    this._register(this.model.onResults(() => { ... }));
}

// GOOD — MutableDisposable ensures max 1 listener
private readonly _searchListener = this._register(new MutableDisposable());

startSearch() {
    this._searchListener.value = this.model.onResults(() => { ... });
}

```

When the event should only fire once per method call, combine `Event.once()` with `MutableDisposable` — this auto-removes the listener after the first invocation while still guarding against repeated calls:

```
private readonly _searchListener = this._register(new MutableDisposable());

startSearch() {
    this._searchListener.value = Event.once(this.model.onResults)(() => { ... });
}

```

**Validated by**: PR #283466 — Terminal find widget leaked 1 listener per search.

### Step 4: Model-Tied DisposableStores

**Rule**: When creating a `DisposableStore` tied to a model's lifetime, register `model.onWillDispose(() => store.dispose())` to the store itself.

```
const store = new DisposableStore();
store.add(model.onWillDispose(() => store.dispose()));
store.add(model.onDidChange(() => { ... }));

```

**Validated by**: Pattern used in `chatEditingSession.ts`, `fileBasedRecommendations.ts`, `testingContentProvider.ts`.

### Step 5: Resource Pool Patterns

**Rule**: When using factory methods that create pooled objects (lists, trees), disposables must be registered to the individual item, not the pool class.

```
// BAD — registers to pool, never cleaned per item
createItem() {
    const item = new Item();
    this._register(item.onEvent(() => { ... }));
    return item;
}

// GOOD — wrap with item-scoped disposal
createItem(): IDisposable & Item {
    const store = new DisposableStore();
    const item = new Item();
    store.add(item.onEvent(() => { ... }));
    return { ...item, dispose: () => store.dispose() };
}

```

**Validated by**: PR #290505 — Chat content parts CollapsibleListPool and TreePool leaked disposables.

### Step 6: Test Validation

**Rule**: Every test suite that creates disposable objects must call `ensureNoDisposablesAreLeakedInTestSuite()`.

```
import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../base/test/common/utils.js';

suite('MyFeature', () => {
    ensureNoDisposablesAreLeakedInTestSuite();

    test('does something', () => {
        // test disposables are tracked automatically
    });
});

```

## Quick Reference

Scenario
Pattern
Anti-Pattern

DOM events
`addDisposableListener()`
`.onclick =`, `addEventListener()`

One-time events
`Event.once(event)(handler)`
`event(handler)` for lifecycle

Repeated methods
`MutableDisposable` or return `IDisposable`
`this._register()` in non-constructor

Model lifecycle
`store.add(model.onWillDispose(...))`
Forgetting cleanup

Pooled objects
Item-scoped `DisposableStore`
Pool-scoped `this._register()`

Tests
`ensureNoDisposablesAreLeakedInTestSuite()`
No leak checking

## Verification

After fixing leaks, verify by:

- Checking listener counts before/after repeated operations

- Running `ensureNoDisposablesAreLeakedInTestSuite()` in tests

- Confirming object counts stabilize (don't grow linearly with usage)

Weekly Installs431Repository[microsoft/vscode](https://github.com/microsoft/vscode)GitHub Stars183.5KFirst SeenFeb 24, 2026Security Audits[Gen Agent Trust HubPass](/microsoft/vscode/memory-leak-audit/security/agent-trust-hub)[SocketPass](/microsoft/vscode/memory-leak-audit/security/socket)[SnykPass](/microsoft/vscode/memory-leak-audit/security/snyk)Installed oncursor431amp430codex430gemini-cli430opencode430github-copilot430

---
*Source: https://skills.yangsir.net/skill/daily-memory-leak-audit*
*Markdown mirror: https://skills.yangsir.net/api/skill/daily-memory-leak-audit/markdown*