2. Memory Management

Generational GC: Minor Collection

midjvm-internalsmemory-management

Most objects die young -- that's the generational hypothesis, and it's why the JVM splits its heap into a small young generation (collected often, cheaply) and an old generation (collected rarely, expensively). A minor collection is a COPYING collector: it doesn't scan the whole young generation looking for garbage to reclaim -- instead, it traces the LIVE objects from a set of roots and copies only those into a fresh space. Everything else -- every dead object -- is simply left behind, untouched. When the trace finishes, the entire old semispace (dead objects and all) is abandoned at once. This is exactly why a minor GC's cost is proportional to how much data SURVIVED, not to how large the heap is.

Implement minor_gc(heap, roots, promotion_threshold):

  • Trace every object reachable from roots through heap.from_space (following each visited object's "refs" list). Objects not reachable from any root must never be copied into to_space, old_gen, or inspected beyond that initial reachability trace.
  • For each live object, its new age is age + 1. If that new age is >= promotion_threshold, copy it into heap.old_gen (still at its new age); otherwise copy it into heap.to_space at its new age.
  • After every live object has been copied, heap.from_space becomes what was just built in heap.to_space, and heap.to_space resets to {} -- ready for the next collection.

Return {"visited": int, "promoted": [id, ...], "survived": [id, ...]}. "visited" is the number of objects the trace actually touched -- this should equal the number of LIVE objects, regardless of how many dead objects also happened to be sitting in from_space.

Example

heap = Heap()
heap.allocate("A", refs=["B"])
heap.allocate("B", refs=[])
heap.allocate("garbage", refs=[])   # unreachable from any root

stats = minor_gc(heap, roots=["A"], promotion_threshold=100)
stats["visited"]        # -> 2 (A and B -- garbage was never touched)
"garbage" in heap.from_space   # -> False
heap.from_space["A"]["age"]    # -> 1

Constraints

  • The object graph may contain cycles -- trace with a visited set.
  • promotion_threshold is compared against an object's age AFTER this collection increments it, not its age before.
  • roots may reference ids not present in heap.from_space (e.g. already promoted to old_gen in an earlier collection) -- skip those rather than erroring.

Real-world grounding

Real HotSpot also tracks old-generation-to-young-generation pointers via a card table / remembered set (so roots aren't only the explicit stack/register set -- an old object holding a reference into the young generation counts too) -- this exercise takes roots as a given, simplified input rather than deriving it from a card table.

hints
minor_gc.pysign in to run
Loading...
test result

This is a preview. Sign in to run this exercise against the real tests.