OpenClaw テストヒープリーク は何をしますか?
テストメモリ調査にはこのスキルを使用してください。ヒープスナップショットが利用可能な場合、RSSのみから推測しないでください。スナップショット名の差分は、retainerまたはdominatorがそれを裏付けるまでは、トリアージの証拠であって証明ではないものとして扱ってください。
最初に ../openclaw-test-performance/SKILL.md を読み、現在のテストパフォーマンスコマンドと証明ルーティングを確認してください。
ランタイム修正(例:ゲートウェイのような長時間稼働サービスにおけるクロージャリーク)については、以下の ランタイム修正の検証 を参照してください。ここでは、単体テストのプロファイリングワークフローではなく、専用のハーネスを使用します。
ワークフロー
-
まず問題の形状を再現します。
- 実際のエントリポイントとワーカー予算に合わせます。幅広い unit-fast ベースライン(設定ごとの最大RSSとファイル別のタイミング)を取得するには、以下から開始します:
pnpm test:perf:groups \ --config test/vitest/vitest.unit-fast.config.ts \ --allow-failures \ --output .artifacts/test-perf/unit-fast-memory.json- 疑わしいファイルについては、そのファイルを1ワーカーで再実行し、wall/RSSの証拠を収集します:
/usr/bin/time -l pnpm test <file> --maxWorkers=1 --reporter=verbose。 - 現在の
pnpm testの実行はscripts/test-projects.mtsによって計画されています。表示されたVitest設定またはシャードを記録し、レポートが設定固有またはワーカー予算固有である場合、その形状を保存しておきます。
-
利用可能な最強のヒープ証拠を収集します。
pnpm test:perf:profile:runner -- --output-dir .artifacts/test-perf/vitest-runner-profile -- <file>を実行し、CPUプロファイルと単体ランナーのサンプリングヒーププロファイルを取得します。DevToolsでヒーププロファイルを開き、最大の割り当てファミリーを調査します。- サンプリング
.heapprofile出力は.heapsnapshotではありません。スナップショット差分ヘルパーに渡さないでください。 - 専用ハーネスまたは他の既知のプロデューサーが繰り返し
.heapsnapshotファイルを生成する場合、同じPIDからのスナップショットを.agents/skills/openclaw-test-heap-leaks/scripts/heapsnapshot-delta.mjsで比較します。 - スナップショットまたはヒーププロファイルが利用できない場合、RSSの増加は有用なトリアージ証拠ですが、リークの分類は結論が出せないままにしておきます。
-
修正を選択する前に増加を分類します。
- 増加がVite/Vitest変換後のソース文字列、
Module、system / Context、バイトコード、ディスクリプタ配列、またはプロパティマップによって支配されている場合、長期稼働ワーカーにおけるモジュールグラフの保持増加として扱います。 - 増加がアプリケーションオブジェクト、キャッシュ、バッファ、サーバーハンドル、タイマー、モック状態、sqlite状態、または類似のランタイムオブジェクトによって支配されている場合、クリーンアップまたはライフサイクルリークとして扱います。
- 名前が曖昧な場合は、確定的なラベル付けを控え、DevToolsでretainer/dominatorを調査し、トップの差分を確認します。
- 増加がVite/Vitest変換後のソース文字列、
-
適切なレイヤーを修正します。
- 共有ワーカーにおける変換モジュールの保持増加が疑われる場合:
- 所有するVitest設定と
scripts/test-projects.test-support.mjs内のプロセスチャンキングを調査します。同じ形状の証拠が共有ワーカーの保持を原因と示している場合にのみ、そこでプロセスのライフタイムまたはプロジェクトの所有権を修正します。 test/vitest/vitest.unit-fast-isolated.config.tsは、監査済みの状態を持つテスト(新しいモジュールグラフが必要)向けです。汎用的なメモリホットスポットリストとして使用しないでください。
- 所有するVitest設定と
- 実際のリークの場合:
- 該当するテストまたはランタイムのクリーンアップパスにパッチを当てます。
- 欠落している
afterEach/afterAll、モジュールリセットのギャップ、保持されたグローバル状態、解放されていないDBハンドル、またはファイルを超えて存続するリスナー/タイマーを探します。
- 共有ワーカーにおける変換モジュールの保持増加が疑われる場合:
-
最も直接的な証明で検証します。
- 同じグループ化またはスコープ指定されたコマンドを再実行し、max-RSSの傾向またはOOMが減少したことを確認します。
- 専用プロデューサーがヒーププロファイルまたはスナップショットを生成する場合、同じプロデューサーを繰り返し、同等のアーティファクトを比較します。
- ルーティングまたは設定の変更については、期待されるVitest設定またはシャードが起動し、影響を受けるテストが完了することを確認します。
ヒューリスティック
- すべてをリークと呼称しないでください。分離されていない共有Vitestプロジェクトでの増加は、アプリケーションオブジェクトのリークではなく、ワーカーのライフタイム問題である可能性があります。
scripts/test-projects.mts、scripts/test-group-report.mts、scripts/run-vitest-profile.mtsが現在の実行、グループ化RSS、プロファイルのエントリポイントです。[test] starting ...行は、再現するVitest設定またはシャードを識別します。.artifacts/vitest-shard-timings.jsonはスケジューリングのための設定/シャードの所要時間を保存します。ファイルレベルのメモリホットスポットや動作マニフェストではありません。- 同じワーカーPID内で複数の間隔にわたって同じ保持オブジェクトファミリーが増加する場合、直感よりもスナップショットを信頼し、不明な呼び出しはretainerの証拠で確認します。
スナップショット比較
- 直接比較:
node .agents/skills/openclaw-test-heap-leaks/scripts/heapsnapshot-delta.mjs before.heapsnapshot after.heapsnapshot
- 1つのレーン内のPIDごとに最も古い/最新のスナップショットを自動選択:
node .agents/skills/openclaw-test-heap-leaks/scripts/heapsnapshot-delta.mjs --lane-dir <snapshot-directory>
- 便利なフラグ:
--top 40--min-kb 32--pid 16133
最初にプラスの差分を読んでください。モジュール変換アーティファクトの大きなプラス成長は、共有プロセスのライフタイムまたはプロジェクトの所有権を示します。ランタイムオブジェクトの大きなプラス成長は、実際のリークを示唆します。名前だけで解決できない場合は、DevToolsで同じスナップショットペアを開き、トップの行のretainer/dominatorを調査してから根本原因を宣言してください。
ランタイム修正の検証(テストメモリ以外)
上記のワークフローは、Vitestワーカーメモリ増加の診断用です。ランタイム/クロージャ修正が実際にキャプチャされた状態を解放することを検証するには、専用ハーネスを使用します:
pnpm leak:embedded-run—scripts/embedded-run-abort-leak.tsを実行します。runEmbeddedAttemptを模倣した関数スコープ内でN回の中断実行をループし、ヒープスナップショットを書き込み、FinalizationRegistryを使用した追跡インスタンスカウントとRSS差分に基づいて保持増加のPASS/FAIL判定を報告します。
モード:
closure-extracted(デフォルト)— 修正後の形状(モジュールスコープのヘルパー)。closure-inline— 修正前の形状(ランナースコープ内のクロージャ)。感度チェックとして使用:合格した場合、バグを修正したのではなく、ハーネスを壊したことになります。synthetic-leak— モジュールレベルのバケットを介して意図的に保持します。実際の修正でPASSを信頼する前に、ハーネスがリークを検出できることを確認するために使用します。
スナップショットは .tmp/embedded-run-abort-leak/ に配置されます。上記と同じスクリプトで差分を取ります:
node .agents/skills/openclaw-test-heap-leaks/scripts/heapsnapshot-delta.mjs \
.tmp/embedded-run-abort-leak/baseline-*.heapsnapshot \
.tmp/embedded-run-abort-leak/batch-N-*.heapsnapshot --top 30
別のランタイムリークを修正する場合は、このハーネスを改造するのではなく、このハーネスに新しいものを追加してください。フィクスチャ関数は、リークが存在する関数のレキシカルスコープを模倣する必要があり、汎用的な中断ループであってはなりません。
出力の期待値
このスキルを使用する場合、以下を報告してください:
- 正確な再現コマンド。
- 再現されたVitest設定またはターゲット、およびスナップショットが利用可能な場合は比較したPID。
- ヒーププロファイルまたはスナップショット差分からの、支配的な保持オブジェクトファミリー(利用可能な場合)。
- 問題が実際のリークである可能性が高いのか、共有ワーカーのモジュール増加保持である可能性が高いのか、さらにretainer/dominatorがそれを確認したかどうか。
- 具体的な修正または影響軽減パッチ。
- 何を検証したか、およびスナップショットのオーバーヘッドにより何を検証できなかったか。