SuperAPI AI 工具集

openclaw-test-heap-leaks

测试与质量

查看项目

更新于 10-16 10:37

技能介绍

用途

这是一个用于测试内存问题调查的技能,适用于 OpenClaw 仓库中与测试相关的内存增长分析,包括 pnpm test 内存增长、Vitest worker OOM,以及可疑的 RSS 上升。技能本身明确要求:当堆快照可用时,不要仅凭 RSS 猜测;在 retainers 或 dominators 提供支持之前,应把快照名称的增量仅当作分诊证据,而不是证据本身。

工作流程

1. 先复现失败形态

尽可能匹配真实入口点。对于 Linux CI 风格的单元测试失败,从以下命令开始:

pnpm canvas:a2ui:bundle && OPENCLAW_TEST_MEMORY_TRACE=1 OPENCLAW_TEST_HEAPSNAPSHOT_INTERVAL_MS=60000 OPENCLAW_TEST_HEAPSNAPSHOT_DIR=.tmp/heapsnap OPENCLAW_TEST_WORKERS=2 OPENCLAW_TEST_MAX_OLD_SPACE_SIZE_MB=6144 pnpm test

保持 OPENCLAW_TEST_MEMORY_TRACE=1 开启,以便包装器在输出快照的同时打印每个文件的 RSS 摘要。如果报告涉及特定 shard 或 worker 预算,需保留该形态。

2. 分析快照前,确认真实 lane 名称

从 [test-parallel] start ... 行或 pnpm test --plan 中识别真实的 lane 名称。不要假设只有一个 unit-fast lane;本地计划常会拆分为 unit-fast-batch-*。

3. 等待重复快照后再下结论

从同一 lane 至少取两个间隔。比较真实 lane 目录(如 .tmp/heapsnap/unit-fast-batch-2/)中同一 PID 的快照。使用 .agents/skills/openclaw-test-heap-leaks/scripts/heapsnapshot-delta.mjs 直接比较两个文件,或比较某个 lane 目录中每个 PID 的最早/最晚一对快照。如果该辅助脚本提示存在 transformed-module 保留,需在 DevTools 的 retainers/dominators 中确认顶部条目后再宣布问题已解决。

4. 在决定修复前先对增长分类

  • 若增长由 Vite/Vitest 的 transformed source 字符串、Module、system / Context、bytecode、descriptor 数组或 property map 主导,视为长期存活 worker 中可能的保留模块图增长。
  • 若增长由应用对象、缓存、缓冲区、server handle、定时器、mock 状态、sqlite 状态或类似运行时对象主导,视为可能的清理或生命周期泄漏。
  • 若名称含义模糊,不要给出自信的标签,转而在 DevTools 中检查顶部增量的 retainers/dominators。

5. 修复正确的层面

针对共享 worker 中可能的保留 transformed-module 增长:

  • 优先考虑基于时序和热点的调度修复。检查该文件是否已出现在 test/fixtures/test-timings.unit.json 中,以及在手工编辑行为覆盖之前是否应先用 scripts/test-update-memory-hotspots.mjs 刷新已测量的热点清单。
  • 仅当时序驱动的剥离不足时,才通过更新 test/fixtures/test-parallel.behavior.json 将热点文件移出真正的共享 lane。
  • 对于单独运行安全但会撑大共享 worker 堆的文件,优先使用 singletonIsolated。
  • 如果某文件本应因时序被剥离,却未出现在 test/fixtures/test-timings.unit.json 中,应明确指出。缺失的时序是一个调度盲点。

针对真实泄漏:修补涉及问题的测试或运行时清理路径。查找缺失的 afterEach/afterAll、模块重置缺口、被保留的全局状态、未释放的 DB handle,或在该文件结束后仍存活的 listener/定时器。

6. 用最直接的证据验证

如果套件仍能在合理时间内完成,重新运行目标 lane 或文件并启用堆快照。如果快照开销使测试超过 Vitest 超时,则回退到同 lane 但不启用快照,确认 RSS 趋势或 OOM 已减少。对于仅修改包装器的改动,至少要验证预期的 lane 能启动且快照文件被写出。

启发式经验

不要把一切都称为泄漏。在此仓库中,unit-fast 或 unit-fast-batch-* 的大幅增长可能是 worker 生存期问题,而非应用对象泄漏。scripts/test-parallel.mjs 和 scripts/test-parallel-memory.mjs 是包装器诊断的主要控制点。[test-parallel] start ... 与 [test-parallel][mem] summary ... 打印的 lane 名称会告诉你应聚焦何处。当一两个文件占据了大部分增量且它们缺失于 timings 时,通过隔离它们来降低影响通常是第一个务实的修复。当同一 worker PID 中相同的保留对象族在多个间隔中持续增长时,相信快照而非直觉,然后用 retainer 证据确认含糊的判断。

快照比较

直接比较:

node .agents/skills/openclaw-test-heap-leaks/scripts/heapsnapshot-delta.mjs before.heapsnapshot after.heapsnapshot

在一个 lane 内自动选择每个 PID 的最早/最晚快照:

node .agents/skills/openclaw-test-heap-leaks/scripts/heapsnapshot-delta.mjs --lane-dir .tmp/heapsnap/unit-fast-batch-2

可用标志:

  • --top 40
  • --min-kb 32
  • --pid 16133

先读取顶部正增量。模块转换产物的大幅正增长提示应做 lane 隔离;运行时对象的大幅正增长提示真实泄漏。如果仅凭名称无法定论,在 DevTools 中打开同一对快照并检查顶部行的 retainers/dominators,然后再宣布根因。

输出预期

使用该技能时,需报告:精确的复现命令;比较了哪个 lane 和 PID;快照增量中主导的保留对象族;问题是可能的真实泄漏还是可能的共享 worker 保留模块增长,以及 retainers/dominators 是否已确认;具体的修复或降低影响的补丁;已验证了什么,以及快照开销导致无法验证什么。