Why Generational Garbage Collection Boosts JVM Performance
This article explains the rationale behind generational garbage collection in the JVM, describes the Young, Old, and Permanent generations, details Scavenge and Full GC processes, and compares serial, parallel, and concurrent collectors to help developers choose the optimal GC strategy.
Why Generational GC?
Generational garbage collection is based on the fact that objects have different lifetimes, allowing the JVM to apply distinct collection strategies for short‑lived and long‑lived objects, thereby improving collection efficiency.
During Java program execution, many objects are created. Business‑related objects such as HTTP session data, threads, and socket connections tend to live longer, while temporary objects like short‑lived String instances are created and discarded quickly.
If the heap were collected as a whole without distinguishing object ages, each GC cycle would take longer and waste effort traversing long‑lived objects that remain unchanged. Generational GC partitions the heap into separate regions, applying the most suitable algorithm to each.
How Generational GC Works
The JVM heap is divided into three generations: Young Generation, Old Generation, and Permanent Generation. The Permanent Generation stores class metadata and has little impact on GC of Java objects. The Young and Old generations are critical for GC performance.
Young Generation
All newly created objects are allocated in the Young Generation, which aims to quickly collect short‑lived objects. It consists of an Eden space and two Survivor spaces. Objects are initially placed in Eden; when Eden fills, surviving objects are copied to a Survivor space. When a Survivor space fills, its survivors move to the other Survivor space, and eventually to the Old (Tenured) Generation after several GC cycles.
Old Generation
Objects that survive multiple Young Generation collections are promoted to the Old Generation, where they remain for a longer period.
Permanent Generation
Stores static metadata such as class definitions. It does not significantly affect GC of regular objects, but applications that dynamically generate classes (e.g., Hibernate) may need a larger Permanent Generation, configurable via -XX:MaxPermSize=<N>.
When GC Is Triggered
Because objects are segregated by generation, the JVM uses two main GC types:
Scavenge GC
Triggered when Eden cannot allocate a new object. It collects the Young Generation, discarding dead objects and moving survivors to Survivor spaces, without affecting the Old Generation. This frequent, fast collection requires an algorithm optimized for speed.
Full GC
Collects the entire heap (Young, Old, and Permanent). It is slower and should be minimized. Common causes include:
Old Generation becoming full
Permanent Generation becoming full
Explicit call to System.gc() Dynamic changes in heap allocation after the previous GC
Choosing the Right GC Algorithm
Serial Collector
Uses a single thread for all GC work. It offers high efficiency on single‑processor machines or small heaps (~100 MB) but cannot leverage multiple CPUs.
Parallel Collector
Performs parallel collection of the Young Generation, reducing GC pause times on multi‑CPU systems. It can also collect the Old Generation in parallel (enabled with -XX:+UseParallelOldGC). The number of GC threads can be set with -XX:ParallelGCThreads=<N>.
Configuration options include:
Maximum GC pause time : -XX:MaxGCPauseMillis=<N> Throughput : -XX:GCTimeRatio=<N> (e.g., -XX:GCTimeRatio=19 means 5 % of time spent in GC)
Concurrent Collector
Executes most GC work concurrently with the application, minimizing pause times—ideal for latency‑sensitive, large‑scale applications. Enabled with -XX:+UseConcMarkSweepGC. It reduces Old Generation pause time by using a separate GC thread, though occasional short pauses still occur.
Concurrent collectors reserve about 20 % of heap space for “floating garbage” that appears during a GC cycle, and they require enough free heap to avoid “Concurrent Mode Failure,” which forces a full stop‑the‑world pause. The start point can be tuned with -XX:CMSInitiatingOccupancyFraction=<N>.
Summary
Serial Collector
Best for small data sets (~100 MB) on single‑processor machines or when response time is not critical.
Not suitable for larger applications.
Parallel Collector
Ideal for throughput‑oriented workloads on multi‑CPU servers (e.g., batch processing, scientific computing).
May increase application pause time during GC.
Concurrent Collector
Fits latency‑sensitive, medium‑to‑large applications (e.g., web servers, telecom switches, IDEs) where short pause times are essential.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
ITFLY8 Architecture Home
ITFLY8 Architecture Home - focused on architecture knowledge sharing and exchange, covering project management and product design. Includes large-scale distributed website architecture (high performance, high availability, caching, message queues...), design patterns, architecture patterns, big data, project management (SCRUM, PMP, Prince2), product design, and more.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
