Skip to main content

electron-heap

Use when analyzing a V8/Chrome/Electron .heapsnapshot file — memory leak hunting, detached DOM nodes, "why is this object retained", growing heap, retainer paths.

소스 정보

저장소
keybase/client
최근 소스 활동
2026년 7월 10일 12:12
감지된 SKILL.md 언어
영어
스타
9,271
포크
1,289

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

파일 탐색기
4 개 파일

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
electron-heap
description
Use when analyzing a V8/Chrome/Electron .heapsnapshot file — memory leak hunting, detached DOM nodes, "why is this object retained", growing heap, retainer paths.
# Heap Snapshot Analysis Parse DevTools `.heapsnapshot` files with Node scripts in `scripts/` — no DevTools UI needed. Snapshots are one big JSON: flat `nodes`/`edges` arrays. 100MB file ≈ 1.2M nodes, parses in ~30s. ## Workflow 1. **Overview** — object counts, sizes, detached DOM, big strings: ```bash node --max-old-space-size=8192 scripts/heap-stats.js <file.heapsnapshot> ``` 2. **Pick suspects** from output (see interpretation table), then trace retention: ```bash node --max-old-space-size=8192 scripts/heap-retainers.js <file.heapsnapshot> '<name-substring>' \ [--detached] [--type=object|native|closure] [--samples=N] [--props] \ [--avoid=InspectorDOMAgent,DevToolsSession,DocumentState] [--js-only] ``` - `--avoid=...` skips retainer nodes by name substring. Re-run with known-benign anchors avoided to see what *else* retains the object. - `--js-only` finds pure-JS retention paths (no native intermediates) — distinguishes app leaks from Blink-internal retention. - `--props` dumps property edges (e.g. Error `message`, ref `current`). Both scripts require `scripts/snapshot-lib.js` (parser + reverse-edge index + BFS path-to-root). ## Interpreting results | Signal | Meaning | |---|---| | Thousands of `Error` + huge `system / StackFrameInfo`, message `react-stack-top-frame`, retained via `_debugStack` | React 19 **dev-build** owner-stack instrumentation. Not a leak; absent in prod. | | Retainer path through `blink::InspectorDOMAgent` / `DevToolsSession` | DevTools itself retains it (snapshot artifact — DevTools must be open to snapshot). Ignore; re-run with `--avoid`. | | Path through `blink::DocumentState` → form control | Blink session-history form-state keeps removed input alive. Browser-internal, bounded. | | Path through `blink::FrameSelection → SelectionEditor → Range` | Page selection/caret still points into detached tree. Released on next selection change; can force with `blur()`/`getSelection().removeAllRanges()` on unmount. | | Detached DOM with **only native** retainer paths (`--js-only` finds nothing) | Not an app JS leak. One live leaf (via parent/child member pointers) pins the whole detached tree. | | Detached DOM with a JS path (fiber `memoizedState`, module map, store, cache) | Real app leak — fix the JS retainer. | | `FiberNode` via `__reactFiber$` expando on a retained DOM node | Normal: React never deletes expandos; fiber lives as long as its DOM node. Fix the DOM retention, not the fiber. | | `PerformanceMeasure` accumulating under `blink::UserTiming` | `performance.measure()` entries never cleared (React dev tracks or app perf code). Bounded noise unless growing. | | `system / ExternalStringData` large | Script sources + big JSON strings (e.g. emoji data). Usually expected. | ## Gotchas - `edges[].to_node` is a byte offset into `nodes` — divide by node-field count (lib handles this). - Shortest retainer path ≠ only path. Kill one anchor and the next takes over — enumerate direct retainers before concluding. - Everything in a snapshot is live by definition; "leak" means *unexpected* retainer, not unreachable memory. - Skip `weak` edges when tracing (lib does). - Comparing two snapshots (before/after) beats staring at one: diff constructor counts from `heap-stats.js` runs.
GitHub에서 보기