Garbage Collection (GC) in Java is a memory management feature of the JVM that automatically reclaims memory used by objects no longer reachable in a program. It allows developers to focus on writing business logic without worrying about memory allocation and deallocation, unlike in languages like C or C++.
1. What is Garbage Collection?
Garbage Collection is a process of identifying and deleting objects that are no longer in use to free up memory. An object becomes eligible for garbage collection when no active part of the program can access it.
Example:
String s = new String("hello");
s = null; // Now "hello" object is eligible for GC
2. Why is Garbage Collection Important?
- Avoids memory leaks
- Improves application performance
- Reduces developer effort by eliminating manual memory deallocation
- Prevents crashes due to memory exhaustion
3. When is an Object Eligible for Garbage Collection?
An object becomes eligible when:
- There are no references to it from any active part of code.
- It’s part of an island of objects that refer to each other but not from any reachable thread.
- The object has been explicitly set to null.
Example:
Employee e = new Employee();
e = null; // eligible for GC
4. GC Process Breakdown
1. Mark Phase
- JVM identifies all reachable objects starting from root references (threads, static fields, method stack).
- It recursively visits all connected objects.
2. Sweep Phase
- JVM removes all unreachable objects.
- The memory these objects occupy is now considered free.
3. Compact Phase
- After sweeping, JVM compacts memory by moving live objects to eliminate fragmentation.
- This helps avoid OutOfMemoryErrors due to heap fragmentation.
4. Promotion
- Objects surviving multiple GC cycles in Young Gen are promoted to Old Gen.
5. Types of Garbage Collection
– Minor GC (Young Generation Collection)
- Quick and frequent.
- Triggers when Eden space fills up.
- Survivors are moved to Survivor or Old Gen.
– Major/Full GC
- Affects the entire heap (Young + Old Gen).
- Slower and causes application pause.
- Usually triggered when Old Gen is full.
6. Garbage Collector Algorithms
Java offers the following GC implementations. You can select the appropriate one using JVM flags (e.g., -XX:+UseG1GC
).
a. Serial Garbage Collector (UseSerialGC
)
Description:
- Uses a single thread for all GC activities.
- Performs stop-the-world collections, pausing all application threads.
Best For:
- Simple, single-threaded environments.
- Small-scale desktop or embedded applications.
Drawbacks:
- Not suitable for large heap sizes or multi-threaded applications.
- Long pause times.
Enable with:
-XX:+UseSerialGC
b. Parallel Garbage Collector (UseParallelGC
)
Description:
- Also known as the Throughput Collector.
- Uses multiple threads for Minor and Major GC.
- Still causes stop-the-world pauses.
Best For:
- High-throughput applications where occasional long pauses are acceptable (e.g., batch jobs, backend services).
Drawbacks:
- May not be suitable for low-latency apps due to longer pause durations.
Enable with:
-XX:+UseParallelGC
c. CMS (Concurrent Mark Sweep) Collector (UseConcMarkSweepGC
)
Deprecated since Java 9 and removed in Java 14
Description:
- Performs most of the GC work concurrently with the application threads.
- Designed to reduce pause times by doing mark and sweep in parallel.
Best For:
- Low-latency applications like web servers.
Drawbacks:
- Fragmentation of heap memory.
- High CPU usage during concurrent phases.
- Deprecated and replaced by G1 GC.
Enable with:
-XX:+UseConcMarkSweepGC
d. G1 Garbage Collector (UseG1GC
)
Description:
- Default GC in Java since Java 9.
- Divides the heap into equal-sized regions.
- Performs GC incrementally to avoid long pause times.
- Supports concurrent and parallel phases.
Best For:
- Applications that need balanced throughput and low pause times.
- Ideal for apps with large heap sizes (multi-GB).
Drawbacks:
- Slightly more CPU usage than Parallel GC.
- More complex tuning compared to Serial/Parallel GC.
Enable with:
-XX:+UseG1GC
e. Z Garbage Collector (UseZGC
)
Description:
- Designed for sub-millisecond pause times.
- Scales well to heaps from a few GB to terabytes.
- Performs almost all operations concurrently.
Best For:
- Real-time and ultra-low latency systems.
- Financial services, high-frequency trading, streaming apps.
Drawbacks:
- Requires newer JVM versions (Java 11+ for Linux, Java 15+ for macOS/Windows).
- Slightly higher memory overhead.
Enable with:
-XX:+UseZGC
f. Shenandoah GC (UseShenandoahGC
)
Description:
- Developed by Red Hat.
- Compacts memory concurrently with the application.
- Offers pause times in the range of milliseconds, regardless of heap size.
Best For:
- Large heap applications needing predictable pause times.
- Modern distributed systems.
Drawbacks:
- Still maturing in terms of ecosystem and tooling.
- Requires Java 12+ (improved in Java 17+).
Enable with:
-XX:+UseShenandoahGC
Summary Table: Java Garbage Collectors
GC Type | Concurrency | Target Use Case | Pause Time | Available Since | Notes |
---|---|---|---|---|---|
Serial | Single-threaded | Simple apps, embedded systems | High | Java 1.2 | Good for small heaps |
Parallel | Multi-threaded | Batch processing | Medium-High | Java 1.4 | High throughput focus |
CMS (Deprecated) | Concurrent | Web servers | Low | Java 1.4 | Removed in Java 14 |
G1 | Concurrent + Parallel | General-purpose | Low-Medium | Java 7 | Default since Java 9 |
ZGC | Mostly concurrent | Real-time apps, huge heaps | Very Low | Java 11+ | Pause time < 10ms |
Shenandoah | Fully concurrent | Predictable latency apps | Very Low | Java 12+ | Compacting GC |
7. How to Trigger GC (Manually)
Although not recommended, you can request GC using:
System.gc();
Runtime.getRuntime().gc();
However, the JVM may ignore the request. Always rely on JVM’s GC rather than forcing it manually.
8. GC Root References
GC uses special references known as GC Roots to determine object reachability. Common GC roots include:
- Active thread stacks
- Static fields
- JNI references
- Local variables in native methods
If an object is reachable from any GC Root, it’s considered “live.”
9. Tuning Garbage Collection
Use these flags to monitor and tune GC:
Basic Tuning:
-Xms512m
→ Set initial heap size-Xmx2048m
→ Set max heap size
GC Algorithm Switches:
-XX:+UseSerialGC
-XX:+UseParallelGC
-XX:+UseG1GC
-XX:+UseZGC
-XX:+UseShenandoahGC
Logging:
-verbose:gc
-XX:+PrintGCDetails
-Xlog:gc
Example:
java -Xms512m -Xmx2048m -XX:+UseG1GC -Xlog:gc MyApp
10. Memory Leaks in Java
Even with GC, Java apps can suffer from memory leaks if you hold onto references unnecessarily.
Common Causes:
- Static variables holding large objects
- Caching without eviction
- Unclosed resources (e.g.,
InputStream
) - Listeners or observers not removed
Use tools like:
jvisualvm
Eclipse MAT (Memory Analyzer Tool)
jconsole
Key Points
- Java’s GC automatically cleans unused objects to free memory.
- JVM uses a generation-based memory model: Young, Old, and Metaspace.
- Objects are promoted from Young to Old Gen if they survive GC cycles.
- GC Types: Minor GC, Major/Full GC.
- Java offers multiple GC algorithms, including G1, ZGC, and Shenandoah.
- GC tuning helps optimize pause time, throughput, or latency depending on the app.
- Use GC logs and monitoring tools to detect memory issues and optimize usage.