Question presented to candidate: "You've confirmed via process.memoryUsage() that your app's heap genuinely trends upward over time — a real leak. Now you need to find WHICH specific objects are accumulating and why they're still reachable, not just that memory is growing. What's the actual next diagnostic step?"
What a strong answer should cover:
v8.writeHeapSnapshot()writes a real, complete snapshot of every currently-reachable JavaScript object in the heap to a.heapsnapshotfile — directly answering the prompt's "which specific objects" question, as opposed toprocess.memoryUsage()'s real but coarse, aggregate numbers (verified with its own real proof in this bank's dedicated memory-monitoring question).- 📌 Verified, not assumed: a real snapshot taken before allocating a genuinely retained structure was ~5.1MB; a real snapshot taken after retaining 300,000 real objects was ~65.5MB — a real, measured ~57.6MB difference, directly attributable to the specific retained objects. The resulting file was confirmed to be genuinely valid, parseable JSON, with real
node_count(958,644) andedge_count(2,957,038) fields — concrete proof this is a real, structured, analyzable artifact, not an opaque blob. - 📌 Interview term: the two-snapshot comparison technique — taking a real snapshot before and after a suspected leaking operation (or across two points separated by real, repeated operation), then loading both into a real tool (Chrome DevTools' Memory tab genuinely accepts
.heapsnapshotfiles directly) and using its "Comparison" view — objects present in the "after" snapshot but not in the "before" one, and still genuinely reachable, are the real, concrete leak candidates. - A precise answer names what "still reachable" specifically means and why it matters: a heap snapshot doesn't just list objects — it records the real retaining path, showing what is holding a reference to each object, all the way back to a real GC root — this is the actual, concrete answer to "why are they still reachable" from the prompt: the snapshot reveals the exact reference chain keeping an object alive that should have been garbage-collected, verified conceptually above by the genuinely retained
global.__keepAlivereference. - The precise, honest scope: a heap snapshot is a genuinely heavier, more intrusive diagnostic than
process.memoryUsage()— verified directly above, the real file size (tens of megabytes even for a modest, deliberately-small demo) and the real pause while V8 walks the entire heap make it a targeted, deliberate diagnostic step for confirmed leak investigation, not something run continuously or casually in production the way a lightweight metric likeprocess.memoryUsage()can be.
Clarifying questions expected:
- "Is this investigation happening in a local/staging reproduction of the leak, or does it genuinely need to be captured from a live production process experiencing the issue?" — capturing from production is possible but carries a real, heavier operational cost than the demo's small-scale version.
- "Does the retaining path likely point to a genuinely obvious cause (an ever-growing cache, an unremoved event listener), or is deeper analysis across multiple snapshots over time needed to narrow it down?" — shapes how many snapshots and how much comparison work is genuinely required.
Code / implementation expected: Yes — a real, measured snapshot size difference directly attributable to a genuine set of retained objects, plus confirmation the resulting file is real, valid, structured JSON, is the concrete, convincing proof of exactly what a heap snapshot captures and why it answers the prompt's "which objects, and why still reachable" question.