Fuites de Tas des Tests OpenClaw
Utilisez cette compétence pour les investigations mémoire des tests. Ne vous fiez pas uniquement au RSS lorsque des snapshots de tas sont disponibles. Considérez les deltas de noms de snapshots comme des indices de triage, non comme une preuve, jusqu'à ce que les reteneurs ou les dominators soutiennent l'appel.
Lisez d'abord ../openclaw-test-performance/SKILL.md pour les commandes actuelles de performance des tests et le routage des preuves.
Pour les correctifs d'exécution (par exemple, les fuites de fermeture dans les services à longue durée comme la passerelle), voir Validation des correctifs d'exécution ci-dessous — cela utilise un harnais dédié plutôt que le workflow de profilage de test unitaire.
Workflow
-
Reproduisez d'abord la forme défaillante.
-
Faites correspondre le point d'entrée réel et le budget de workers. Pour une large base unitaire rapide avec RSS max par configuration et chronométrage par fichier principal, commencez par :
pnpm test:perf:groups \ --config test/vitest/vitest.unit-fast.config.ts \ --allow-failures \ --output .artifacts/test-perf/unit-fast-memory.json -
Pour un fichier suspecté, relancez ce fichier avec un seul worker et collectez les preuves wall/RSS :
/usr/bin/time -l pnpm test <fichier> --maxWorkers=1 --reporter=verbose. -
L'exécution actuelle de
pnpm testest planifiée parscripts/test-projects.mts. Enregistrez la configuration ou le fragment (shard) Vitest affiché et préservez cette forme lorsque le rapport est spécifique à une configuration ou à un budget de workers.
-
-
Collectez les preuves de tas les plus solides disponibles.
- Exécutez
pnpm test:perf:profile:runner -- --output-dir .artifacts/test-perf/vitest-runner-profile -- <fichier>pour obtenir un profil CPU ainsi qu'un profil de tas par échantillonnage de l'exécuteur unitaire. Ouvrez le profil de tas dans DevTools et inspectez les plus grandes familles d'allocations. - La sortie
.heapprofilepar échantillonnage n'est pas un.heapsnapshot; ne la passez pas à l'utilitaire de delta de snapshot. - Lorsqu'un harnais dédié ou un autre producteur connu émet des fichiers
.heapsnapshotrépétés, comparez les snapshots du même PID avec.agents/skills/openclaw-test-heap-leaks/scripts/heapsnapshot-delta.mjs. - Si aucun snapshot ou profil de tas n'est disponible, la croissance du RSS est une preuve de triage utile, mais maintenez la classification de la fuite comme non concluante.
- Exécutez
-
Classez la croissance avant de choisir un correctif.
- Si la croissance est dominée par les chaînes source transformées par Vite/Vitest,
Module,system / Context, le bytecode, les tableaux de descripteurs ou les maps de propriétés, traitez-la comme une croissance probable du graphe de modules retenus dans les workers à longue durée. - Si la croissance est dominée par les objets de l'application, les caches, les buffers, les handles de serveur, les timers, l'état des mocks, l'état SQLite ou des objets d'exécution similaires, traitez-la comme une fuite probable de nettoyage ou de cycle de vie.
- Si les noms sont ambigus, ne tirez pas de conclusion définitive et inspectez les reteneurs/dominators dans DevTools pour les principaux deltas.
- Si la croissance est dominée par les chaînes source transformées par Vite/Vitest,
-
Corrigez la bonne couche.
- Pour une croissance probable des modules transformés retenus dans les workers partagés :
- Inspectez la configuration Vitest propriétaire et le découpage des processus dans
scripts/test-projects.test-support.mjs. Corrigez la durée de vie du processus ou la propriété du projet uniquement lorsque la preuve de même forme montre que la rétention du worker partagé en est la cause. test/vitest/vitest.unit-fast-isolated.config.tsest destiné aux tests avec état audités qui nécessitent un nouveau graphe de modules. Ne l'utilisez pas comme une liste générique de points chauds mémoire.
- Inspectez la configuration Vitest propriétaire et le découpage des processus dans
- Pour les véritables fuites :
- Corrigez le test impliqué ou le chemin de nettoyage d'exécution.
- Recherchez les
afterEach/afterAllmanquants, les lacunes de réinitialisation de module, l'état global retenu, les handles de base de données non libérés ou les écouteurs/timers qui survivent au fichier.
- Pour une croissance probable des modules transformés retenus dans les workers partagés :
-
Vérifiez avec la preuve la plus directe.
- Relancez la même commande groupée ou ciblée et confirmez que la tendance du RSS max ou que l'OOM est réduite.
- Lorsqu'un producteur dédié émet des profils de tas ou des snapshots, répétez le même producteur et comparez les artefacts équivalents.
- Pour les modifications de routage ou de configuration, vérifiez que la configuration ou le fragment Vitest attendu démarre et que les tests affectés se terminent.
Heuristiques
- N'appelez pas tout une fuite. La croissance dans un projet Vitest partagé non isolé peut être un problème de durée de vie du worker plutôt qu'une fuite d'objet applicatif.
scripts/test-projects.mts,scripts/test-group-report.mtsetscripts/run-vitest-profile.mtssont les points d'entrée actuels pour l'exécution, le RSS groupé et le profilage.- Les lignes
[test] starting ...identifient la configuration ou le fragment Vitest à reproduire. .artifacts/vitest-shard-timings.jsonstocke les durées des configurations/fragments pour l'ordonnancement. Ce n'est pas un manifeste de point chaud mémoire ou de comportement au niveau fichier.- Lorsque les mêmes familles d'objets retenus croissent sur plusieurs intervalles dans le même PID de worker, faites confiance aux snapshots plutôt qu'à l'intuition, puis confirmez les appels ambigus avec des preuves de reteneurs.
Comparaison de Snapshots
- Comparaison directe :
node .agents/skills/openclaw-test-heap-leaks/scripts/heapsnapshot-delta.mjs before.heapsnapshot after.heapsnapshot
- Sélection automatique des snapshots les plus anciens/les plus récents par PID dans une même voie :
node .agents/skills/openclaw-test-heap-leaks/scripts/heapsnapshot-delta.mjs --lane-dir <snapshot-directory>
- Drapeaux utiles :
--top 40--min-kb 32--pid 16133
Lisez d'abord les deltas positifs les plus importants. Une forte croissance positive dans les artefacts de transformation de modules indique un problème de durée de vie du processus partagé ou de propriété du projet ; une forte croissance positive dans les objets d'exécution suggère une véritable fuite. Si les noms seuls ne suffisent pas, ouvrez la même paire de snapshots dans DevTools et inspectez les reteneurs/dominators pour les premières lignes avant de déclarer la cause racine.
Validation des correctifs d'exécution (pas la mémoire des tests)
Le workflow ci-dessus est destiné à diagnostiquer la croissance mémoire des workers Vitest. Pour valider qu'un correctif d'exécution/fermeture libère réellement l'état capturé, utilisez le harnais dédié :
pnpm leak:embedded-run— exécutescripts/embedded-run-abort-leak.ts. Boucle N exécutions avortées dans une portée en forme de fonction imitantrunEmbeddedAttempt, écrit des snapshots de tas et rapporte un verdict RÉUSSI/ÉCHEC sur la croissance de rétention en utilisantFinalizationRegistrypour le comptage d'instances suivies plus le delta RSS.
Modes :
closure-extracted(par défaut) — forme du correctif de production (assistant à la portée du module).closure-inline— forme avant correctif (fermeture à l'intérieur de la portée de l'exécuteur). Utilisez-le comme un test de sensibilité : s'il réussit, vous avez cassé le harnais, pas corrigé un bug.synthetic-leak— retient délibérément via un compartiment au niveau du module. Utilisez-le pour confirmer que le harnais peut détecter les fuites avant de faire confiance à un RÉUSSI sur un véritable correctif.
Les snapshots atterrissent dans .tmp/embedded-run-abort-leak/. Diffusez avec le même script que ci-dessus :
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
Lorsque vous corrigez une autre fuite d'exécution, ajoutez un nouveau harnais à côté de celui-ci plutôt que de l'adapter. La fonction de l'appareillage doit imiter la portée lexicale de la fonction où se trouve la fuite, pas être une boucle d'abandon générique.
Attentes de Sortie
Lorsque vous utilisez cette compétence, indiquez :
- La commande de reproduction exacte.
- Quelle configuration Vitest ou quelle cible a été reproduite, et quel PID a été comparé lorsque des snapshots étaient disponibles.
- Les familles d'objets retenus dominantes du profil de tas ou du delta de snapshot, lorsqu'elles sont disponibles.
- Si le problème est probablement une véritable fuite ou une croissance probable du module retenu par le worker partagé, plus si les reteneurs/dominators l'ont confirmé.
- Le correctif concret ou le patch de réduction d'impact.
- Ce que vous avez vérifié, et ce que la surcharge de snapshot vous a empêché de vérifier.