Garbage Collection in Java

Garbage Collection in Java is an automated memory management process that handles memory allocation and deallocation, freeing developers from manual memory management. The Java Virtual Machine (JVM) runs GC to identify and remove objects no longer in use, preventing memory leaks and optimizing performance.

Garbage collection is crucial in modern programming languages, especially for managing memory in large applications. For instance, in a web server handling thousands of requests, efficient garbage collection can significantly affect performance and memory usage. If developers had to manually manage memory, it could lead to errors and application crashes due to memory leaks or improper deallocation.

The garbage collection process in Java is not only about reclaiming memory but also about optimizing it. By understanding the different phases and algorithms used in garbage collection, developers can write more efficient code that minimizes memory consumption.

Generational Garbage Collection

Understanding garbage collection can also help in debugging memory-related issues. For example, if a Java application is consuming too much memory, a developer can investigate the garbage collection logs to determine what objects are not being collected and why.

Java’s heap is divided into generations to optimize garbage collection efficiency:

  1. Young Generation:
    • Newly created objects reside here.
    • Divided into Eden (where objects are born) and Survivor Spaces (S0, S1).
    • Frequent minor GCs clean short-lived objects here.
  2. Old Generation (Tenured):
    • Objects that survive multiple minor GC cycles in the Young Generation are promoted here.
    • These are old candidates (long-lived objects).
    • Cleaned by major GC (slower, but less frequent).
  3. Permanent Generation/Metaspace (for class metadata).

How Does Java Garbage Collection Work?

  • Eligibility Check: An object becomes eligible for GC when no active references point to it (e.g., when set to null or goes out of scope).
  • Reclamation: The GC algorithm (e.g., G1, Parallel, or ZGC) automatically reclaims memory occupied by unused objects.

Benefits of Garbage Collection

  • Prevents memory leaks and manual malloc/free errors.
  • Boosts productivity by handling memory cleanup.
  • Enhances application stability and performance.

Example of Garbage Collection in Java

public class GCExample {  
    public static void main(String[] args) {  
        GCExample obj = new GCExample();  
        obj = null; // Object now eligible for GC  
        System.gc(); // Suggests JVM trigger GC (not guaranteed)  
    }  

    @Override  
    protected void finalize() {  
        System.out.println("Object cleaned by GC!");  
    }  
}  

Explanation:

  1. An object obj is created and later set to null, making it eligible for GC.
  2. System.gc() suggests JVM run GC (Note: execution isn’t guaranteed).
  3. The deprecated finalize() method (for demonstration only) prints a message if the object is collected.

Output:

You may see an output like given below.

warning: [removal] finalize() in Object has been deprecated and marked for removal
    protected void finalize() {  
                   ^
1 warning
Object cleaned by GC!

When you execute above program, you may not see the message Object cleaned by GC! printed in your first attempt. Because System.gc() may not be executed always. Hence, try couple of times and you will se this message printed when JVM run GC.

Moreover, garbage collection is not a one-size-fits-all solution. Different applications have different needs. For example, a real-time system might require a low-latency garbage collector like ZGC, while a batch processing application might benefit from a collector that emphasizes throughput, such as Parallel GC.

Types of Java Garbage Collectors

  • Serial GC: For single-threaded apps.
  • Parallel GC: Uses multiple threads (default for high throughput).
  • G1 GC: Balances latency and throughput for large heaps.
  • ZGC: Low-latency GC for massive memory sizes.

Key Concepts in Garbage Collection

  1. Heap Memory:
    • The area of memory where objects are stored.
    • Divided into two main parts: Young Generation (for new objects) and Old Generation (for long-lived objects).
  2. Young Generation:
    • Where new objects are created.
    • Garbage collection here is called Minor GC and is fast.
  3. Old Generation:
    • Where objects that survive multiple garbage collections in the Young Generation are moved.
    • Garbage collection here is called Major GC or Full GC and is slower.
  4. Stop-the-World (STW):
    • During garbage collection, the JVM pauses the application to clean up memory.
    • The goal of modern garbage collectors is to minimize these pauses.

One thing, we need to understand is, most of the time we as a developer don’t need to do any extra tuning to GC. Java Virtual Machine itself takes care everything when to release unwanted memory or not.

Conclusion

Java Garbage Collection simplifies memory management, ensuring efficient resource use and reducing developer workload.

In addition to understanding the benefits, it’s also important to be aware of the limitations of garbage collection. For instance, while GC can prevent memory leaks, it cannot eliminate them entirely if the code retains strong references to objects that are no longer needed.

Furthermore, developers can also tune garbage collectors based on the specific requirements of their applications, such as adjusting the heap size or modifying other JVM parameters to optimize performance.

Lastly, garbage collection is an area that continues to evolve. Newer algorithms and techniques are consistently being developed to improve efficiency and performance, reflecting the ongoing trend towards faster and more resource-efficient applications in the Java ecosystem.

Reference:

Sharing Is Caring: