Diagnose memory leaks in the Qwen Code CLI using heap snapshots and the chrome-devtools CLI. Use when investigating high memory usage, unbounded growth, or suspected object retention issues.
76
96%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Diagnose memory leaks in the Qwen Code Node.js CLI by capturing heap snapshots
and analyzing retained object sizes via chrome-devtools CLI tooling.
chrome-devtools CLI (from chrome-devtools-mcp package). If not found,
install with: npm i chrome-devtools-mcp@latest -g after user confirmation.
See https://github.com/ChromeDevTools/chrome-devtools-mcp/blob/main/docs/cli.md--heapsnapshot-signal support)Use tmux so you can interact with the TUI and trigger snapshots from another pane. Use the tmux-real-user-testing helper script:
HELPER=.qwen/skills/tmux-real-user-testing/scripts/tmux-real-user-log.sh
eval "$(bash "$HELPER" start memleak . \
env QWEN_CODE_NO_RELAUNCH=true NODE_OPTIONS=--heapsnapshot-signal=SIGUSR2 \
npm run dev)"
echo "SESSION=$SESSION OUTDIR=$OUTDIR"The eval exports SESSION and OUTDIR. Note: shell environment does not
persist across separate tool calls — save the session name from the output and
use it explicitly in subsequent commands.
Notes:
npm run dev runs from TypeScript source via tsx — no build step needed and
changes to core/cli are reflected immediately.QWEN_CODE_NO_RELAUNCH=true prevents the CLI from spawning a child process,
so PID management is simpler.NODE_OPTIONS propagates the flag through npm → tsx → node.Get the PID of the actual node process. With npm run dev, there's a process
chain (npm → node scripts/dev.js → tsx → node CLI), so walk the tree to the
innermost node child:
NODE_PID=$(bash .qwen/skills/memory-leak-debug/scripts/find-leaf-node.sh "<session-name>")To profile the production bundle instead (e.g., verifying tree-shaking):
npm run bundle first, then use
env QWEN_CODE_NO_RELAUNCH=true node --heapsnapshot-signal=SIGUSR2 dist/cli.js
as the command. Since node is the direct pane process, PID discovery is simpler:
NODE_PID=$(tmux list-panes -t "<session-name>" -F '#{pane_pid}')Drive the TUI via tmux (see tmux-real-user-testing skill for patterns). Take snapshots at intervals to compare:
kill -USR2 $NODE_PID # snapshot 1 (baseline)
# ... use the CLI via tmux send-keys ...
kill -USR2 $NODE_PID # snapshot 2 (after activity)
# ... more activity ...
kill -USR2 $NODE_PID # snapshot 3 (confirm growth trend)Snapshots are written to the CLI's working directory as
Heap.<timestamp>.<pid>.<seq>.heapsnapshot.
chrome-devtools start --experimentalMemory --headless --no-usage-statisticsThis starts the daemon in file-analysis mode — no browser or live Node
connection is needed. The memory tools work entirely on .heapsnapshot files.
chrome-devtools load_memory_snapshot /abs/path/to/snapshot.heapsnapshotReturns total heap size, V8 heap breakdown, node count.
chrome-devtools get_memory_snapshot_details /abs/path/to/snapshot.heapsnapshotOutput is CSV: uid, className, count, selfSize, maxRetainedSize.
Compare across snapshots to find classes whose count or retained size grows unboundedly.
chrome-devtools get_nodes_by_class /abs/path/to/snapshot.heapsnapshot <uid>Where <uid> is from the get_memory_snapshot_details output. Returns
individual instances with their id, retainedSize, and nodeIndex.
chrome-devtools get_node_retainers /abs/path/to/snapshot.heapsnapshot <nodeId>Where <nodeId> is the id field from get_nodes_by_class. Shows what holds
the object alive — follow the chain to find the root retention path.
Common patterns:
performance.measure() → measureEntryBuffer).The retainer chain tells you what holds the object; the class aggregate growth rate tells you how fast it leaks.
After applying the fix:
npm run bundleHELPER=.qwen/skills/tmux-real-user-testing/scripts/tmux-real-user-log.sh
bash "$HELPER" finish "<session-name>" "<outdir>"
chrome-devtools stop
rm *.heapsnapshot # if no longer neededSee examples/react-reconciler-performance-measure-leak.md for the ink 7
upgrade leak that caused ~143 MB retention from PerformanceMeasure objects.
8878264
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.