JVM Performance Optimization Part 3 – Garbage Collection
This article explains Java's memory model and garbage collection mechanisms, covering reference counting, tracing collectors, copying and mark‑sweep algorithms, parallel and concurrent collectors, generational GC, and compression techniques, while discussing their trade‑offs, tuning considerations, and impact on application performance.
This article is the third part of a JVM performance optimization series, introducing Java's memory model and garbage collection (GC) mechanisms for beginners.
GC is the process of reclaiming memory occupied by unreachable Java objects; reachable objects are retained while unreachable ones are freed for new allocations.
Understanding the Java heap, which is allocated via the -Xmx flag, is essential because a full heap triggers GC, and GC only runs at safe points when all threads are at a safe point.
GC must quickly free unreachable objects to prevent OOM errors and must minimize impact on latency and throughput.
Two main GC approaches : reference counting and tracing collectors. Reference counting tracks the number of references to each object and immediately frees objects with zero references, but it cannot handle cyclic references. Tracing collectors start from root objects, mark reachable objects, and then reclaim unmarked memory.
Tracing collector algorithms include copying and mark‑sweep. Copying collectors move live objects from a “from” space to a “to” space, eliminating fragmentation but requiring stop‑the‑world pauses and sufficient space in the “to” region.
Mark‑sweep collectors, widely used in production JVMs (e.g., CMS, G1, ZGC), mark live objects and then sweep unmarked regions, placing reclaimed memory into free lists; they can suffer from long pause times proportional to heap size and live data.
Parallel collectors run GC phases on multiple threads but are still stop‑the‑world, affecting latency‑sensitive applications. Concurrent collectors overlap GC work with application threads, requiring heuristics to decide safe points for phases and to avoid long re‑mark loops.
Generational GC divides the heap into young and old generations, assuming most objects die young; promotion failures and fragmentation can still occur in the old generation, requiring tuning of generation sizes and promotion rates.
Compression (heap compaction) is the only way to fully eliminate fragmentation by moving live objects together, but it incurs stop‑the‑world pauses that grow with the amount of live data.
The article concludes that while tuning can delay OOM errors, over‑tuning is risky; understanding GC algorithms, their trade‑offs, and appropriate tuning for the workload is essential for optimal Java application performance.
Qunar Tech Salon
Qunar Tech Salon is a learning and exchange platform for Qunar engineers and industry peers. We share cutting-edge technology trends and topics, providing a free platform for mid-to-senior technical professionals to exchange and learn.
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.