memory management
intermediateGarbage Collection
Free heap memory automatically by identifying objects no longer reachable from GC roots — and choose the GC algorithm that fits your latency vs throughput target.
Garbage collection is Java freeing memory for you. It finds objects your program can no longer reach, and reclaims the space they were using.
A janitor that throws out anything no longer connected to the main building (GC roots). G1 cleans one room at a time during business hours. ZGC works alongside everyone without disturbing them.
Key Concepts
1
Interview questions are almost never about how it frees memory. They are about the pauses: collecting
sometimes stops your application, and you need to know why, for how long, and what to do.
2
How it decides what to free. It does not count references. It starts from a set of definitely-alive
places — local variables on each thread's stack, static fields, and a few others — and follows every
reference from there, marking everything it can reach.
3
Anything not marked is unreachable, and unreachable means nobody can ever use it again. That is what gets
freed.
4
This is why two objects pointing at each other are still collected. Neither is reachable from a starting
point, so neither is marked, so both go.
5
Why memory is split into generations. Almost all objects die almost immediately. A method makes a few
objects, returns, and they are garbage.
6
So the heap has a young area and an old area. New objects go into the young area, which is collected often.
Because nearly everything there is already dead, the collector only has to copy out the few survivors,
which is quick.
7
An object that survives several young collections is moved to the old area, which is collected rarely and
more expensively.
8
The collectors, and what each is for.
Serial stops everything, one thread. Tiny heaps only.
Parallel stops everything, many threads. Best total
throughput; fine for batch jobs.
G1 (default) splits the heap into regions and collects the
emptiest first; aims at a pause target you set,
usually 200 ms.
ZGC does nearly all its work while your application
runs. Pauses under 10 ms even on huge heaps, at a
few percent throughput.
Shenandoah same idea as ZGC.9
Choose from the requirement, not the name. A nightly batch job can afford a two-second pause and wants
maximum throughput. An API where the 99th percentile matters cannot, and should pay a few percent for short
pauses.
10
How to tell whether you have a leak. Do not watch memory usage; it rises and falls normally. Watch the
level it returns to after a full collection.
11
A healthy application drops back to the same floor each time. A leaking one has a floor that creeps upward
over hours. That rising floor is the signal, and it means something is holding references it no longer
needs.
12
Sizing the heap. Too small and the collector runs constantly. Too large and each old-area collection
takes longer — and if the heap does not fit in physical memory, the machine starts swapping, which is
catastrophic because the collector touches memory all over the place.
13
Set the starting size equal to the maximum size in production, so the JVM never pauses to resize.
14
System.gc() is a suggestion, and usually a bad one. It asks for the most expensive kind of collection
available, and the JVM may ignore it anyway. Code that calls it in a loop turns a mild memory problem into
a pause problem.
System.gc()
15
What the interviewer is probing.1. "How does it know what to free?" Probing: reachability. Stalls: "Reference counting." *Moves
up:* mark from live starting points; unreachable is garbage, which is why cycles are collected.
16
2. "Why split young and old?" Probing: the observation behind it. Stalls: "For organisation."
Moves up: most objects die young, so collecting a small young area frequently reclaims most garbage
cheaply.
17
3. "Which collector would you choose?" Probing: requirement first. Stalls: naming one. Moves up:
pause target versus throughput, with the workload stated; G1 as a sensible default.
18
4. "How do you find a leak?" Probing: method. Stalls: "Increase the heap." Moves up: watch the
post-collection floor over hours, then take two heap snapshots and compare what grew.
19
5. "Does System.gc() help?" Probing: judgement. Stalls: "It frees memory." Moves up: it
requests the most expensive collection and may be ignored; it usually makes pauses worse.
System.gc()
20
Collectors, and what each is for21
Collector Pause behaviour Throughput Use when
------------------------------------------------------------------
Serial stop-the-world, grows good tiny heaps, single
with heap core, containers
Parallel stop-the-world, multi- best batch jobs; pauses
threaded are acceptable
G1 (default) target-driven, often very good general purpose,
50-200 ms heaps 4 GB+
ZGC < 10 ms, near heap- ~5% less latency-critical,
independent large heaps
Shenandoah < 10 ms, concurrent ~5% less same, OpenJDK
compaction22
Object lifecycle23
allocate -> Eden
minor GC: live objects copied Eden -> Survivor
survive N collections (MaxTenuringThreshold, default 15)
-> promoted to Old
Old fills -> major/mixed collection (the expensive one)24
Reading GC logs (-Xlog:gc*)
frequent minor GCs -> high allocation rate; look for
short-lived garbage in hot loops
growing old-gen after each
full GC -> a real leak; take a heap dump
long pauses, low throughput -> heap too small, or the live set is
genuinely large
"to-space exhausted" (G1) -> promotion failing; raise heap or
lower the pause target's ambition25
Flags worth knowing
-XX:+UseG1GC -XX:MaxGCPauseMillis=200
-XX:+UseZGC
-Xms == -Xmx avoids resize pauses
-Xlog:gc*:file=gc.log always on in production