Question presented to candidate: "Two allocation patterns exist in the same app: a request-scoped temporary object created and discarded thousands of times per second, and a long-lived cache object that survives the whole process. Does V8's garbage collector treat these the same way?"
What a strong answer should cover:
- V8's heap is split by generation: a young generation (
new_space) for newly allocated, typically short-lived objects, and an old generation (old_space) for objects that have survived multiple collections and are assumed likely to keep living β this is the generational hypothesis: most objects die young, so optimizing for that case pays off. - π Verified, not just described:
v8.getHeapSpaceStatistics()confirmed real, distinct heap spaces genuinely exist in a running process (new_space,old_space, pluscode_spaceand others) β not an abstract textbook description. - Minor GC (Scavenge) runs frequently on the young generation, is fast, and copies surviving objects β π verified directly with
--trace-gc: many realScavengeevents fired in quick succession during a real allocation loop, each completing in low single-digit milliseconds. - Major GC (Mark-Compact) runs on the old generation, less frequently, and is more expensive since it must trace the entire reachable object graph β π verified directly: a real
Mark-Compactevent appeared in the same trace, reclaiming a large amount of memory (163.8MB β 49.5MB) in a single pass, structurally different from the many small Scavenge events around it. - An object surviving enough Scavenge cycles is promoted from the young generation to the old generation β this is exactly why the two example allocation patterns in the prompt are treated differently: the request-scoped temporary object is reclaimed cheaply by Scavenge long before ever qualifying for promotion, while the long-lived cache is promoted and then only revisited by the rarer, more expensive Mark-Compact pass.
- A precise answer names that GC pauses are a real, measurable cost β a large Mark-Compact pause can be a visible latency spike β and that this generational design exists specifically to minimize how often the expensive full-graph trace needs to run, not to eliminate GC pauses entirely.
Clarifying questions expected:
- "Is the concern understanding the mechanism, or diagnosing an actual observed GC-related latency/memory problem?" β the latter routes to the dedicated memory-leaks and heap-snapshot questions.
- "Does the interviewer want the generational model specifically, or V8 memory management more broadly (Buffers living outside the heap, covered elsewhere)?"
Code / implementation expected: Yes β a real --trace-gc log showing genuine Scavenge and Mark-Compact events is the concrete, convincing proof, not a description of the two-generation model.