Was macht OpenClaw Test Heap Leaks?
Verwenden Sie diese Skill für Untersuchungen von Test-Speicherproblemen. Ziehen Sie keine Schlüsse allein aus RSS, wenn Heap-Snapshots verfügbar sind. Behandeln Sie Snapshot-Name-Deltas als Triage-Hinweise, nicht als Beweise, bis Retainer oder Dominatoren den Befund stützen.
Lesen Sie zuerst ../openclaw-test-performance/SKILL.md für die aktuellen Test-Performance-Befehle und Beweisrouting.
Für Laufzeit-Fixes (z. B. Closure-Leaks in langlebigen Diensten wie dem Gateway) siehe Validierung von Laufzeit-Fixes unten – dies verwendet eine dedizierte Testumgebung, nicht den Unit-Test-Profiling-Workflow.
Arbeitsablauf
-
Reproduzieren Sie zuerst die fehlerhafte Form.
-
Passen Sie den tatsächlichen Einstiegspunkt und das Worker-Budget an. Für eine breite Unit-Fast-Baseline mit maximalem RSS pro Konfiguration und Datei-Timing beginnen Sie mit:
pnpm test:perf:groups \ --config test/vitest/vitest.unit-fast.config.ts \ --allow-failures \ --output .artifacts/test-perf/unit-fast-memory.json -
Bei einer verdächtigen Datei führen Sie diese mit einem Worker erneut aus und sammeln Wand-/RSS-Beweise:
/usr/bin/time -l pnpm test <datei> --maxWorkers=1 --reporter=verbose. -
Die aktuelle Ausführung von
pnpm testwird vonscripts/test-projects.mtsgesteuert. Notieren Sie die gedruckte Vitest-Konfiguration oder den Shard und bewahren Sie diese Form, wenn der Bericht konfigurations- oder worker-budget-spezifisch ist.
-
-
Sammeln Sie die stärksten verfügbaren Heap-Beweise.
- Führen Sie
pnpm test:perf:profile:runner -- --output-dir .artifacts/test-perf/vitest-runner-profile -- <datei>für ein CPU-Profil plus ein Sampling-Heap-Profil des Unit-Runners aus. Öffnen Sie das Heap-Profil in DevTools und inspizieren Sie die größten Allokationsfamilien. - Die Sampling-
.heapprofile-Ausgabe ist keine.heapsnapshot; übergeben Sie sie nicht an den Snapshot-Delta-Helfer. - Wenn eine dedizierte Testumgebung oder ein anderer bekannter Produzent wiederholte
.heapsnapshot-Dateien ausgibt, vergleichen Sie Snapshots von derselben PID mit.agents/skills/openclaw-test-heap-leaks/scripts/heapsnapshot-delta.mjs. - Wenn kein Snapshot oder Heap-Profil verfügbar ist, ist RSS-Wachstum ein nützlicher Triage-Hinweis, aber behalten Sie die Leck-Klassifizierung als nicht schlüssig bei.
- Führen Sie
-
Klassifizieren Sie das Wachstum, bevor Sie einen Fix wählen.
- Wenn das Wachstum von Vite/Vitest-transformierten Quellstrings,
Module,system / Context, Bytecode, Deskriptor-Arrays oder Property-Maps dominiert wird, behandeln Sie es als wahrscheinliches zurückgehaltenes Modulgraph-Wachstum in langlebigen Workern. - Wenn das Wachstum von App-Objekten, Caches, Puffern, Server-Handles, Timern, Mock-Zustand, SQLite-Zustand oder ähnlichen Laufzeitobjekten dominiert wird, behandeln Sie es als wahrscheinliches Aufräum- oder Lebenszyklus-Leck.
- Wenn die Namen mehrdeutig sind, bleiben Sie vor einer sicheren Kennzeichnung zurück und inspizieren Sie Retainer/Dominatoren in DevTools für die größten Deltas.
- Wenn das Wachstum von Vite/Vitest-transformierten Quellstrings,
-
Beheben Sie die richtige Ebene.
- Bei wahrscheinlichem zurückgehaltenem transformiertem Modulwachstum in gemeinsamen Workern:
- Inspizieren Sie die zugehörige Vitest-Konfiguration und die Prozess-Chunking in
scripts/test-projects.test-support.mjs. Beheben Sie die Prozesslebensdauer oder Projekteigentümerschaft dort nur, wenn die gleiche Form zeigt, dass die gemeinsame Worker-Retention die Ursache ist. test/vitest/vitest.unit-fast-isolated.config.tsist für geprüfte zustandsbehaftete Tests, die einen frischen Modulgraphen benötigen. Verwenden Sie es nicht als generische Memory-Hotspot-Liste.- Bei echten Lecks:
- Patchen Sie den betroffenen Test- oder Laufzeit-Aufräumpfad.
- Suchen Sie nach fehlenden
afterEach/afterAll, Modul-Reset-Lücken, zurückgehaltenem globalen Zustand, nicht freigegebenen DB-Handles oder Listenern/Timern, die die Datei überleben.
-
Verifizieren Sie mit dem direktesten Beweis.
- Führen Sie den gleichen gruppierten oder eingeschränkten Befehl erneut aus und bestätigen Sie, dass der maximale RSS-Trend oder OOM reduziert ist.
- Wenn ein dedizierter Produzent Heap-Profile oder Snapshots ausgibt, wiederholen Sie den gleichen Produzenten und vergleichen Sie äquivalente Artefakte.
- Bei Routing- oder Konfigurationsänderungen verifizieren Sie, dass die erwartete Vitest-Konfiguration oder der Shard startet und die betroffenen Tests abgeschlossen werden.
Heuristiken
- Bezeichnen Sie nicht alles als Leck. Wachstum in einem nicht isolierten gemeinsamen Vitest-Projekt kann ein Worker-Lebensdauer-Problem sein, kein Applikations-Objekt-Leck.
scripts/test-projects.mts,scripts/test-group-report.mtsundscripts/run-vitest-profile.mtssind die aktuellen Ausführungs-, Gruppen-RSS- und Profil-Einstiegspunkte.- Die
[test] starting ...-Zeilen identifizieren die Vitest-Konfiguration oder den Shard zur Reproduktion. .artifacts/vitest-shard-timings.jsonspeichert Konfigurations-/Shard-Dauern für die Planung. Es ist kein Datei-Level-Memory-Hotspot oder Verhaltensmanifest.- Wenn dieselben zurückgehaltenen Objektfamilien über mehrere Intervalle in derselben Worker-PID wachsen, vertrauen Sie den Snapshots mehr als der Intuition, und bestätigen Sie mehrdeutige Befunde mit Retainer-Beweisen.
Snapshot-Vergleich
- Direkter Vergleich:
node .agents/skills/openclaw-test-heap-leaks/scripts/heapsnapshot-delta.mjs before.heapsnapshot after.heapsnapshot
- Automatische Auswahl der frühesten/spätesten Snapshots pro PID innerhalb einer Lane:
node .agents/skills/openclaw-test-heap-leaks/scripts/heapsnapshot-delta.mjs --lane-dir <snapshot-verzeichnis>
- Nützliche Flags:
--top 40--min-kb 32--pid 16133
Lesen Sie zuerst die positiven Top-Deltas. Großes positives Wachstum in Modul-Transform-Artefakten deutet auf gemeinsame Prozesslebensdauer oder Projekteigentümerschaft hin; großes positives Wachstum in Laufzeitobjekten deutet auf ein echtes Leck hin. Wenn die Namen allein nicht ausreichen, öffnen Sie dasselbe Snapshot-Paar in DevTools und inspizieren Sie Retainer/Dominatoren für die oberen Zeilen, bevor Sie die Ursache festlegen.
Validierung von Laufzeit-Fixes (nicht Test-Speicher)
Der obige Arbeitsablauf gilt für die Diagnose von Vitest-Worker-Speicherwachstum. Zur Validierung, dass ein Laufzeit-/Closure-Fix tatsächlich erfassten Zustand freigibt, verwenden Sie die dedizierte Testumgebung:
pnpm leak:embedded-run– führtscripts/embedded-run-abort-leak.tsaus. Durchläuft N abgebrochene Läufe in einem funktionsförmigen Bereich, derrunEmbeddedAttemptnachahmt, schreibt Heap-Snapshots und meldet ein BESTANDEN/FEHLGESCHLAGEN-Urteil über Retentionswachstum unter Verwendung vonFinalizationRegistryfür verfolgte Instanzen-Zählung plus RSS-Delta.
Modi:
closure-extracted(Standard) – Produktions-Fix-Form (Helfer im Modul-Bereich).closure-inline– Vor-Fix-Form (Closure innerhalb des Runner-Bereichs). Als Sensitivitätsprüfung verwenden: Wenn es bestanden wird, haben Sie die Testumgebung kaputt gemacht, nicht einen Bug behoben.synthetic-leak– bewusstes Zurückhalten über einen Modul-Level-Bucket. Verwenden Sie dies, um zu bestätigen, dass die Testumgebung Lecks erkennen kann, bevor Sie einem BESTANDEN auf einem echten Fix vertrauen.
Snapshots landen in .tmp/embedded-run-abort-leak/. Differenzieren Sie mit demselben Skript wie oben:
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
Wenn Sie einen anderen Laufzeit-Leck beheben, fügen Sie eine neue Testumgebung neben dieser hinzu, anstatt sie umzurüsten. Die Fixture-Funktion sollte den lexikalischen Bereich der Funktion nachahmen, in der das Leck lebt, keine generische Abbruch-Schleife sein.
Ausgabeerwartungen
Bei Verwendung dieser Skill berichten Sie:
- Den genauen Reproduktionsbefehl.
- Welche Vitest-Konfiguration oder welches Ziel reproduziert wurde und welche PID verglichen wurde, wenn Snapshots verfügbar waren.
- Die dominanten zurückgehaltenen Objektfamilien aus dem Heap-Profil oder Snapshot-Delta, wenn verfügbar.
- Ob das Problem ein wahrscheinliches echtes Leck oder wahrscheinlich zurückgehaltenes Modulwachstum in gemeinsamen Workern ist, plus ob Retainer/Dominatoren dies bestätigt haben.
- Den konkreten Fix oder die auswirkungsreduzierende Änderung.
- Was Sie verifiziert haben und welcher Snapshot-Overhead Sie daran gehindert hat, etwas zu verifizieren.