Fugas de Heap en Pruebas de OpenClaw
Usa esta habilidad para investigaciones de memoria en pruebas. No te bases solo en RSS cuando haya instantáneas de heap disponibles. Trata los deltas de nombres de instantáneas como evidencia de triaje, no como prueba, hasta que los retenedores o dominadores respalden la conclusión.
Lee primero ../openclaw-test-performance/SKILL.md para conocer los comandos actuales de rendimiento de pruebas y el enrutamiento de pruebas.
Para correcciones en tiempo de ejecución (por ejemplo, fugas en closures en servicios de larga duración como el gateway), consulta Validación de correcciones en tiempo de ejecución más abajo; utiliza un harness dedicado en lugar del flujo de trabajo de perfil de pruebas unitarias.
Flujo de Trabajo
-
Reproduce primero la forma del fallo.
-
Coincide con el punto de entrada real y el presupuesto de workers. Para una línea base amplia de pruebas unitarias rápidas con RSS máximo por configuración y temporización de archivos principales, comienza con:
pnpm test:perf:groups \ --config test/vitest/vitest.unit-fast.config.ts \ --allow-failures \ --output .artifacts/test-perf/unit-fast-memory.json -
Para un archivo sospechoso, vuelve a ejecutar ese archivo con un worker y recopila evidencia de wall/RSS:
/usr/bin/time -l pnpm test <archivo> --maxWorkers=1 --reporter=verbose. -
La ejecución actual de
pnpm testestá planificada porscripts/test-projects.mts. Registra la configuración de Vitest o el shard impreso y conserva esa forma cuando el informe sea específico de la configuración o del presupuesto de workers.
-
-
Recopila la evidencia de heap más sólida disponible.
- Ejecuta
pnpm test:perf:profile:runner -- --output-dir .artifacts/test-perf/vitest-runner-profile -- <archivo>para obtener un perfil de CPU más un perfil de heap por muestreo del runner de pruebas unitarias. Abre el perfil de heap en DevTools e inspecciona las familias de asignación más grandes. - La salida de
.heapprofilepor muestreo no es un.heapsnapshot; no la pases al helper de delta de instantáneas. - Cuando un harness dedicado u otro productor conocido emita archivos
.heapsnapshotrepetidos, compara las instantáneas del mismo PID con.agents/skills/openclaw-test-heap-leaks/scripts/heapsnapshot-delta.mjs. - Si no hay instantáneas ni perfiles de heap disponibles, el crecimiento de RSS es evidencia útil de triaje, pero mantén la clasificación de fuga como no concluyente.
- Ejecuta
-
Clasifica el crecimiento antes de elegir una corrección.
- Si el crecimiento está dominado por cadenas fuente transformadas por Vite/Vitest,
Module,system / Context, bytecode, arreglos de descriptores o mapas de propiedades, trátalo como probable crecimiento de grafo de módulos retenidos en workers de larga duración. - Si el crecimiento está dominado por objetos de la aplicación, cachés, buffers, manejadores de servidor, temporizadores, estado de mocks, estado de sqlite u objetos similares de tiempo de ejecución, trátalo como una probable limpieza o fuga de ciclo de vida.
- Si los nombres son ambiguos, detente antes de una etiqueta confiada e inspecciona retenedores/dominadores en DevTools para los principales deltas.
- Si el crecimiento está dominado por cadenas fuente transformadas por Vite/Vitest,
-
Corrige la capa adecuada.
- Para probable crecimiento de módulos transformados retenidos en workers compartidos:
- Inspecciona la configuración de Vitest propietaria y la división en procesos en
scripts/test-projects.test-support.mjs. Corrige la vida útil del proceso o la propiedad del proyecto allí solo cuando la evidencia de la misma forma muestre que la retención del worker compartido es la causa. test/vitest/vitest.unit-fast-isolated.config.tses para pruebas con estado auditadas que necesitan un grafo de módulos fresco. No lo uses como una lista genérica de puntos calientes de memoria.
- Inspecciona la configuración de Vitest propietaria y la división en procesos en
- Para fugas reales:
- Parchea la prueba implicada o la ruta de limpieza en tiempo de ejecución.
- Busca
afterEach/afterAllfaltantes, brechas en el reinicio de módulos, estado global retenido, manejadores de base de datos no liberados, o listeners/timers que sobreviven al archivo.
- Para probable crecimiento de módulos transformados retenidos en workers compartidos:
-
Verifica con la prueba más directa.
- Vuelve a ejecutar el mismo comando agrupado o con ámbito y confirma que la tendencia de RSS máximo o OOM se ha reducido.
- Cuando un productor dedicado emita perfiles o instantáneas de heap, repite el mismo productor y compara artefactos equivalentes.
- Para cambios de enrutamiento o configuración, verifica que la configuración de Vitest o el shard esperado se inicie y que las pruebas afectadas se completen.
Heurísticas
- No llames a todo fuga. El crecimiento en un proyecto compartido de Vitest no aislado puede ser un problema de vida útil del worker, no una fuga de objetos de la aplicación.
scripts/test-projects.mts,scripts/test-group-report.mtsyscripts/run-vitest-profile.mtsson los puntos de entrada actuales de ejecución, RSS agrupado y perfil.- Las líneas
[test] starting ...identifican la configuración de Vitest o el shard para reproducir. .artifacts/vitest-shard-timings.jsonalmacena las duraciones de configuración/shard para la planificación. No es un mapa de puntos calientes de memoria ni un manifiesto de comportamiento a nivel de archivo.- Cuando las mismas familias de objetos retenidos crecen en múltiples intervalos dentro del mismo PID de worker, confía en las instantáneas sobre la intuición, luego confirma las llamadas ambiguas con evidencia de retenedores.
Comparación de Instantáneas
- Comparación directa:
node .agents/skills/openclaw-test-heap-leaks/scripts/heapsnapshot-delta.mjs before.heapsnapshot after.heapsnapshot
- Selección automática de instantáneas más tempranas/tardías por PID dentro de un carril:
node .agents/skills/openclaw-test-heap-leaks/scripts/heapsnapshot-delta.mjs --lane-dir <directorio-de-instantáneas>
- Banderas útiles:
--top 40--min-kb 32--pid 16133
Lee primero los deltas positivos principales. Un gran crecimiento positivo en artefactos de transformación de módulos apunta a un problema de vida útil del proceso compartido o de propiedad del proyecto; un gran crecimiento positivo en objetos de tiempo de ejecución sugiere una fuga real. Si los nombres por sí solos no lo resuelven, abre el mismo par de instantáneas en DevTools e inspecciona retenedores/dominadores para las filas principales antes de declarar la causa raíz.
Validación de correcciones en tiempo de ejecución (no memoria de pruebas)
El flujo de trabajo anterior es para diagnosticar el crecimiento de memoria de los workers de Vitest. Para validar que una corrección en tiempo de ejecución/closure realmente libera el estado capturado, usa el harness dedicado:
pnpm leak:embedded-run— ejecutascripts/embedded-run-abort-leak.ts. Itera N ejecuciones abortadas en un ámbito con forma de función que imitarunEmbeddedAttempt, escribe instantáneas de heap y reporta un veredicto de PASA/NO PASA sobre el crecimiento de retención usandoFinalizationRegistrypara el conteo de instancias rastreadas más el delta de RSS.
Modos:
closure-extracted(predeterminado) — forma de corrección de producción (helper a nivel de módulo).closure-inline— forma previa a la corrección (closure dentro del ámbito del runner). Úsalo como una comprobación de sensibilidad: si pasa, has roto el harness, no corregido un error.synthetic-leak— retiene deliberadamente a través de un bucket a nivel de módulo. Úsalo para confirmar que el harness puede detectar fugas antes de confiar en un PASA en una corrección real.
Las instantáneas se alojan en .tmp/embedded-run-abort-leak/. Compara con el mismo script que arriba:
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
Al corregir una fuga diferente en tiempo de ejecución, añade un nuevo harness junto a este en lugar de readaptarlo. La función de fixture debe imitar el ámbito léxico de la función donde reside la fuga, no ser un bucle de aborto genérico.
Expectativas de Salida
Al usar esta habilidad, reporta:
- El comando exacto de reproducción.
- Qué configuración de Vitest o target se reprodujo, y qué PID se comparó cuando había instantáneas disponibles.
- Las familias de objetos retenidos dominantes del perfil de heap o del delta de instantáneas, cuando estén disponibles.
- Si el problema es probablemente una fuga real o un probable crecimiento de módulos retenidos en workers compartidos, además de si los retenedores/dominadores lo confirmaron.
- La corrección concreta o el parche de reducción de impacto.
- Lo que verificaste y qué sobrecarga de instantáneas te impidió verificar.