Java Advanced · Ay 1

Garbage Collection & Memory

Goal: understand garbage collection, find memory leaks and use profiling tools. Duration: 120 min

1. Why GC?

In C you free() memory manually: forgetting it leaks memory, freeing twice crashes. Java's garbage collector frees objects that are no longer reachable.

An object is reachable if there is a path from a GC root: local variables on stacks, static fields, active threads, JNI references.

2. Generational hypothesis

Most objects die young.

Heap
├── Young generation
│   ├── Eden          (new objects)
│   └── Survivor S0/S1
└── Old generation    (long-lived objects)
  • Minor GC: cleans young gen often and fast.
  • Objects surviving several minor GCs are promoted to old gen.
  • Major/Full GC: cleans old gen: slower.

3. Garbage collectors

GC Flag Good for
Serial -XX:+UseSerialGC tiny apps, 1 CPU
Parallel -XX:+UseParallelGC batch throughput
G1 (default) -XX:+UseG1GC most server apps
ZGC -XX:+UseZGC very low pauses (< 1 ms), large heaps
Shenandoah -XX:+UseShenandoahGC low pause (Red Hat builds)

Metrics: throughput (time not in GC) vs latency (pause length) vs footprint (memory).

4. GC logs

java -Xlog:gc*:file=gc.log:time,uptime -Xmx512m -jar app.jar
[2.345s] GC(12) Pause Young (Normal) (G1 Evacuation Pause) 245M->38M(512M) 6.712ms

Before → after (heap size), pause time.

5. Memory leaks in Java

Java can still leak: objects stay reachable but are never used again.

Typical causes:

// 1. Growing static collections
public class Cache {
    private static final Map<String, byte[]> CACHE = new HashMap<>();   // never evicted
}

// 2. Listeners never removed
eventBus.register(listener);   // no unregister

// 3. ThreadLocal in thread pools without remove()
private static final ThreadLocal<User> CURRENT = new ThreadLocal<>();

// 4. Keys with broken equals/hashCode in HashMap (duplicates accumulate)

// 5. Unclosed resources (streams, connections)

6. Profiling tools

Tool Use
jps list Java processes
jcmd <pid> GC.heap_info heap summary
jcmd <pid> GC.heap_dump heap.hprof heap dump
jstat -gc <pid> 1000 GC stats every second
VisualVM live CPU/memory, heap dumps
Java Flight Recorder (JFR) + JDK Mission Control production-safe profiling
Eclipse MAT analyse heap dumps: "dominator tree", leak suspects
java -XX:StartFlightRecording=duration=60s,filename=rec.jfr -jar app.jar
java -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp -jar app.jar

7. Hands-on: create and find a leak

public class LeakDemo {
    private static final List<byte[]> LEAK = new ArrayList<>();

    public static void main(String[] args) throws Exception {
        while (true) {
            LEAK.add(new byte[1024 * 1024]);   // 1 MB per iteration, never released
            Thread.sleep(50);
        }
    }
}
  1. Run with -Xmx256m -XX:+HeapDumpOnOutOfMemoryError.
  2. Watch in VisualVM: heap grows and GC can't free it.
  3. Open the dump in MAT/VisualVM: find LEAK holding the arrays.
  4. Fix: bounded cache (e.g. LinkedHashMap with removeEldestEntry, or Caffeine).

8. References types (bonus)

Type Collected when
Strong never while reachable
SoftReference memory is low (caches)
WeakReference at next GC (WeakHashMap)
PhantomReference cleanup tracking

9. Interview corner

  • How does GC decide an object is garbage?
  • What is the difference between minor and full GC?
  • Can Java have memory leaks? Give an example.
  • Which GC would you choose for a payment API with strict latency? (ZGC/G1 with tuned pause goals)

10. Homework

Profile one of your previous projects with JFR: record 60 s, open in JDK Mission Control, and write down the top 3 allocation hotspots and GC pause stats.