memory-leak-audit

作成者: microsoft

メモリリークと破棄に関する問題をコード監査します。イベントリスナー、DOMハンドラー、ライフサイクルコールバックのレビュー時や、リークレポートの修正時に使用します。対象範囲…

npx skills add https://github.com/microsoft/vscode --skill 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

ScenarioPatternAnti-Pattern
DOM eventsaddDisposableListener().onclick =, addEventListener()
One-time eventsEvent.once(event)(handler)event(handler) for lifecycle
Repeated methodsMutableDisposable or return IDisposablethis._register() in non-constructor
Model lifecyclestore.add(model.onWillDispose(...))Forgetting cleanup
Pooled objectsItem-scoped DisposableStorePool-scoped this._register()
TestsensureNoDisposablesAreLeakedInTestSuite()No leak checking

Verification

After fixing leaks, verify by:

  1. Checking listener counts before/after repeated operations
  2. Running ensureNoDisposablesAreLeakedInTestSuite() in tests
  3. Confirming object counts stabilize (don't grow linearly with usage)
  4. For chat-specific leaks: Run the chat memory leak checker via npm run perf:chat-leak (see the chat-perf skill). It sends N messages in a single session, forces GC between each, and uses linear regression on heap/DOM samples to detect per-message growth. A slope above 2 MB/msg indicates a leak. Use --messages 20 --verbose for more accurate results.

microsoftのその他のスキル

oss-growth
microsoft
OSS成長ハッカーのペルソナ
agent-framework-azure-ai-py
microsoft
Microsoft Agent Framework Python SDK(agent-framework-azure-ai)を使用してAzure AI Foundryエージェントを構築します。AzureAIAgentsProviderを使用した永続的なエージェントの作成、ホスト型ツール(コードインタープリター、ファイル検索、ウェブ検索)の使用、MCPサーバーの統合、会話スレッドの管理、ストリーミング応答の実装時に使用します。関数ツール、構造化出力、マルチツールエージェントをカバーします。
development
airunway-aks-setup
microsoft
AKS上でAI Runwayをセットアップ — ベアクラスターからモデル実行まで。クラスター検証、コントローラーインストール、GPU評価、プロバイダー設定、初回デプロイをカバー。対象: 「AI Runwayのセットアップ」「AKSクラスターのオンボード」「AI Runwayのインストール」「airunway setup」「AKSへのモデルデプロイ」「AKSでのGPU推論」「AKSでのKAITOセットアップ」「AKSでのLLM実行」「AKSでのvLLM」「AKSでのモデルサービング設定」「AI Runwayコントローラー」。
devops
appinsights-instrumentation
microsoft
Azure Application Insightsを使用したWebアプリのインストルメンテーションに関するガイダンス。テレメトリパターン、SDKセットアップ、構成リファレンスを提供します。対象: アプリのインストルメンテーション方法、App Insights SDK、テレメトリパターン、App Insightsとは何か、Application Insightsガイダンス、インストルメンテーション例、APMベストプラクティス。
devops
applicationinsights-web-ts
microsoft
Application Insights JavaScript SDK(@microsoft/applicationinsights-web)を使用してブラウザ/Webアプリを計測します。Real User Monitoring(RUM)— ページビュー、クリック、AJAX/fetch依存関係、例外、カスタムイベント、およびバックエンドのOpenTelemetryトレースに関連付けられたブラウザ側のGenAIエージェントトレースに使用します。SDKローダースクリプトとnpmセットアップ、フレームワーク拡張機能(React、React Native、Angular)、Click Analytics、テレメトリ初期化子、およびブラウザから生成されるエージェント/ツール/モデルスパンのOTel GenAIセマンティック規約をカバーします。
devops
azure-ai-anomalydetector-java
microsoft
Azure AI Anomaly Detector SDK for Javaを使用して異常検出アプリケーションを構築します。単変量/多変量異常検出、時系列分析、またはAIを活用したモニタリングを実装する際に使用します。
development
azure-ai-language-conversations-py
microsoft
azure-ai-language-conversations Python SDKを使用して会話言語理解(CLU)を実装します。ConversationAnalysisClientを使用して会話の意図とエンティティを分析する場合、NLP機能を構築する場合、またはアプリケーションに言語理解を統合する場合に使用します。
development
azure-ai-ml-py
microsoft
Azure Machine Learning SDK v2 for Python。MLワークスペース、ジョブ、モデル、データセット、コンピュート、パイプラインに使用します。 トリガー: 「azure-ai-ml」、「MLClient」、「ワークスペース」、「モデルレジストリ」、「トレーニングジョブ」、「データセット」。
development