Why Java Garbage Collection is so Important?
For many, the world of Java is shrouded in mystery and endeavor. One such endeavor is garbage collection.
There is many a viewpoint on garbage collection – whether it is good or bad, when is it needed, how often should it run, how to tune garbage collection operation, how to know when it is not operating as expected, and so on.
In this educational post, we will try to clear the air on Java garbage collection and make it easy for developers and administrators to deal with it.
What is Java Garbage Collection?
Java applications obtain objects in memory as needed. It is the task of garbage collection (GC) in the Java virtual machine (JVM) to automatically determine what memory is no longer being used by a Java application and to recycle this memory for other uses. Because memory is automatically reclaimed in the JVM, Java application developers are not burdened with having to explicitly free memory objects that are not being used.
The GC operation is based on the premise that most objects used in the Java code are short-lived and can be reclaimed shortly after their creation. Because unreferenced objects are automatically removed from the heap memory, GC makes Java memory-efficient.
Garbage collection frees the programmer from manually dealing with memory deallocation. As a result, certain categories of application program bugs are eliminated or substantially reduced by GC:
- Dangling pointer bugs, which occur when a piece of memory is freed while there are still pointers to it, and one of those pointers is dereferenced. By then the memory may have been reassigned to another use with unpredictable results.
- Double free bugs, which occur when the program tries to free a region of memory that has already been freed and perhaps already been allocated again.
- Certain kinds of memory leaks, in which a program fails to free memory occupied by objects that have become unreachable, which can lead to memory exhaustion.
There are two types of garbage collection activity that usually happens in Java:
- A minor or incremental garbage collection is said to have occurred when unreachable objects in the young generation heap memory are removed.
- A major or full garbage collection is said to have occurred when the objects that survived the minor garbage collection and copied into the old generation or permanent generation heap memory are removed. When compared to young generation, garbage collection happens less frequently in old generation.
To free up memory, the JVM must stop the application from running for at least a short time and execute GC. This process is called “stop-the-world.” This means all the threads, except for the GC threads, will stop executing until the GC threads are executed and objects are freed up by the garbage collector.
Modern GC implementations try to minimize blocking “stop-the-world” stalls by doing as much work as possible on the background (i.e. using a separate thread), for example marking unreachable garbage instances while the application process continues to run.
Garbage collection consumes CPU resources for deciding which memory to free. Various garbage collectors have been developed over time to reduce the application pauses that occur during garbage collection and at the same time to improve on the performance hit associated with garbage collection.
The traditional Oracle HotSpot JVM has four ways of performing the GC activity:
- Serial where just one thread executed the GC
- Parallel where multiple minor threads are executed simultaneously each executing a part of GC
- Concurrent Mark Sweep (CMS), which is similar to parallel, also allows the execution of some application threads and reduces the frequency of stop-the-world GC
- G1 which is also run in parallel and concurrently but functions differently than CMS
Many JVMs, such as Oracle HotSpot, JRockit, OpenJDK, IBM J9, and SAP JVM, use stop-the-world GC techniques. Modern JVMs like Azul Zing use Continuously Concurrent Compacting Collector (C4), which eliminates the stop-the-world GC pauses that limit scalability in the case of conventional JVMs.
Why is Monitoring Garbage Collection Important?
Garbage collection can impact the performance of Java application in unpredictable ways. When there is frequent GC activity, it adds a lot of CPU load and slows down application processing. In turn, this leads to slow execution of business transaction and ultimate affects the user experience of end users accessing the Java application.
Excessive garbage collection activity can occur due to a memory leak in the Java application. Insufficient memory allocation to the JVM can also result in increased garbage collection activity. And when excessive garbage collection activity happens, it often manifests as increased CPU usage of the JVM!
For optimal Java application performance, it is critical to monitor a JVM’s GC activity. For good performance, full GCs should be few and far between. The time spent on GC should be low – typically less than 5% and the percentage of CPU spent for garbage collection should be very less (this allows application threads to use almost all the available CPU resources).
What Are the Key Garbage Collection Metrics to Monitor?
To know if garbage collection is creating Java performance problems, you need to track all aspects of the garbage collection activity in the JVM:
| || |
This allows you to identify when garbage collection is taking too long and impacting performance, which will help you to determine the optimal settings for each application based on historical patterns and trends.