Skip to content

Garbage Collection In Java: A Comprehensive Technical Guide

Garbage collection (GC) is an essential but often misunderstood aspect of Java. By automatically managing memory allocation and deallocation, GC frees developers from complex manual memory management. Mastering GC can help optimize application performance and reduce memory issues.

This comprehensive guide will demystify garbage collection in Java through detailed yet accessible explanations of how it works under the hood. Both beginners and experienced developers will come away with a deeper understanding of this critical Java feature.

How Garbage Collection Works in Java

Unlike languages like C and C++, Java handles memory management automatically through garbage collection. Here‘s a quick overview of how it works:

Memory Structure: Stack vs Heap

The JVM divides memory between the stack and the heap:

  • Stack: Fast, last-in-first-out allocation for method calls and local variables
  • Heap: Larger, more complex allocation for object instances

The heap is further divided into young and old generation spaces.

Mark and Sweep Algorithm

The most basic GC algorithm is mark-and-sweep:

  1. Mark: Traverse object graph starting from root references and mark all objects still reachable
  2. Sweep: Free memory for all unmarked objects that are unreachable

This ensures memory safety by deallocating objects no longer needed.

Generational Collection

The heap is further divided into:

  • Young generation (Eden + Survivor spaces) – Frequent minor GC
  • Old generation (Tenured space) – Full GC happens less often

This exploits the generational hypothesis – most objects die young.

Garbage Collection Algorithms

Now let‘s explore common GC algorithms available in Java:

Serial Collector

The simplest collector, meant for small workloads and CPUs with a single core. It freezes all application threads when running.

Enabled with -XX:+UseSerialGC

Parallel Collector

Uses multiple GC threads for higher throughput on multi-core machines. A minor variation on serial GC.

Mostly Concurrent Mark Sweep (CMS)

Designed for low pause times by doing most GC work concurrently with the app threads. Not optimized for throughput.

Enabled with -XX:+UseConcMarkSweepGC

Garbage First Garbage Collector (G1)

Designed for heaps larger than 4GB. Uses many free list spaces and background compaction to reduce fragmentation.

Enabled with -XX:+UseG1GC

There are also several experimental and niche collectors like Shenandoah, ZGC, EpsilonGC. But the above are most commonly used.

Tuning Garbage Collection

GC can be tuned via various JVM options:

-Xms/-Xmx               Heap size

-XX:NewRatio                Young/old gen sizes 

-XX:SurvivorRatio       Eden/survivor space sizes

-XX:MaxTenuringThreshold Move old gen

-XX:+DisableExplicitGC  Disable System.gc()

And many other specialized options per collector algorithm.

Monitoring tools like jstat, jconsole and VisualVM provide insight into GC behavior. This allows tuning GC to reduce pause times or increase throughput.

Conclusion

Understanding garbage collection is key to writing performance Java applications. By leveraging different algorithms and tuning options appropriately for your use case, GC can run smoothly without posing issues.

Common problems like memory leaks can often be diagnosed simply by analyzing and adjusting the GC process. Master its inner workings, and reclaim the huge productivity boost automatic memory management offers.