Working with Garbage Collection
1. Understanding GC Types
| GC | Best For |
|---|---|
| Serial | Tiny heaps, single CPU |
| Parallel | Throughput-oriented batch |
| G1 (default) | Balanced, < 200 ms pauses |
| ZGC | Sub-ms pauses, TB heaps |
| Shenandoah | Low-pause concurrent |
| Epsilon | No-op (testing) |
2. Using G1 Garbage Collector
| Aspect | Detail |
|---|---|
| Default since | Java 9 |
| Region-based | Heap split into ~2048 regions |
| Goal | -XX:MaxGCPauseMillis=200 |
| Mixed collections | Young + selected old regions |
3. Using Low-Latency GCs
| GC | Pause | Notes |
|---|---|---|
| ZGC | < 1 ms | Generational since Java 21 |
| Shenandoah | ~1–10 ms | Concurrent compaction |
| Trade-off | — | ~5–15% throughput cost |
4. Configuring GC Flags (-XX:+UseG1GC, -XX:+UseZGC)
| Flag | Use |
|---|---|
-XX:+UseG1GC | Default since JDK 9 |
-XX:+UseZGC -XX:+ZGenerational | Generational ZGC (Java 21+) |
-XX:+UseShenandoahGC | Shenandoah |
-XX:+UseParallelGC | Throughput |
-XX:+UseSerialGC | Tiny heaps |
5. Understanding GC Phases
| Phase | Detail |
|---|---|
| Marking | Identify live objects from roots |
| Sweeping | Reclaim dead |
| Compaction | Reduce fragmentation |
| Concurrent vs STW | Modern GCs do most work concurrently |
6. Understanding Stop-The-World Events
| Cause | Detail |
|---|---|
| Safepoint | All app threads paused |
| Initial mark / Remark | G1 STW phases |
| Class redefinition | JVMTI agent action |
| Bias revocation | (removed in Java 15+) |
7. Monitoring GC Activity
| Tool | Use |
|---|---|
-Xlog:gc* | Unified logging (Java 9+) |
| jstat -gcutil | % utilization |
| JFR | Recording-based |
| GCViewer / GCEasy | Log analyzers |
8. Tuning GC Parameters
| Flag | Effect |
|---|---|
-XX:MaxGCPauseMillis=N | G1 pause goal |
-XX:G1HeapRegionSize=N | Region size (1–32 MB) |
-XX:InitiatingHeapOccupancyPercent=N | Concurrent cycle trigger |
-XX:ParallelGCThreads / ConcGCThreads | Worker counts |
9. Understanding Finalization
Warning:
Object.finalize() is deprecated since Java 9 and slated for removal. It is unreliable, slow, and can resurrect objects. Use Cleaner or try-with-resources instead.
| Status | Java Version |
|---|---|
| Deprecated | 9 |
| Default disabled | Java 18 (--finalization=disabled) |
| Removal planned | Future LTS |
10. Using Cleaner API
Example: Cleaner
private static final Cleaner CLEANER = Cleaner.create();
public class Resource implements AutoCloseable {
private final Cleaner.Cleanable cleanable;
public Resource() {
cleanable = CLEANER.register(this, () -> release(/* state */));
}
public void close() { cleanable.clean(); }
private static void release(Object state) { /* free native */ }
}
| Aspect | Detail |
|---|---|
| Action | Must NOT reference owner — use static state holder |
| Thread | Runs on cleaner-owned daemon thread |
11. Understanding Reference Types
| Type | GC Behavior |
|---|---|
| Strong | Never collected while reachable |
| Soft | Collected before OOM (memory-sensitive cache) |
| Weak | Collected at next GC |
| Phantom | Enqueued post-finalization; safer than finalize |
12. Using Reference Queues
Example: Phantom + queue
ReferenceQueue<Object> q = new ReferenceQueue<>();
PhantomReference<Object> ref = new PhantomReference<>(target, q);
// background thread:
while (true) { Reference<?> r = q.remove(); cleanup(r); }
| API | Use |
|---|---|
queue.poll() / remove() | Drain enqueued refs |
| Use case | Deterministic cleanup of off-heap resources |