At Stackify, we battle our fair share of code performance problems too, including issues surrounding Java garbage collection. In this post, we’ll take a look at Java garbage collection, how it works, and why it matters.
Java garbage collection is the process by which Java programs perform automatic memory management. Java programs compile to bytecode that can be run on a Java Virtual Machine, or JVM for short. When Java programs run on the JVM, objects are created on the heap, which is a portion of memory dedicated to the program. Eventually, some objects will no longer be needed. The garbage collector finds these unused objects and deletes them to free up memory.
Java garbage collection is an automatic process. The programmer does not need to explicitly mark objects to be deleted. The garbage collection implementation lives in the JVM. Every JVM can implement garbage collection however it pleases. The only requirement is that it should meet the JVM specification. Although there are many JVMs, Oracle’s HotSpot is by far the most common. It offers a robust and mature set of garbage collection options.
While HotSpot has multiple garbage collectors that are optimized for various use cases, all its garbage collectors follow the same basic process. In the first step, unreferenced objects are identified and marked as ready for garbage collection. In the second step, marked objects are deleted. Optionally, memory can be compacted after the garbage collector deletes objects, so remaining objects are in a contiguous block at the start of the heap. The compaction process makes it easier to allocate memory to new objects sequentially after the JVM allocates the memory blocks to existing objects.
All of HotSpot’s garbage collectors implement a generational garbage collection strategy that categorizes objects by age. The rationale behind generational garbage collection is that most objects are short-lived and will be ready for garbage collection soon after creation.
Image via Wikipedia
We can divide the heap into three sections:
During a full garbage collection event, unused objects from all generations are garbage collected.
HotSpot has four garbage collectors:
The biggest benefit of Java garbage collection is that it automatically handles the deletion of unused objects or objects that are out of reach to free up vital memory resources. Programmers working in languages without garbage collection (like C and C++) must implement manual memory management in their code.
Despite the extra work required, some programmers argue in favor of manual memory management over garbage collection, primarily for reasons of control and performance. While the debate over memory management approaches continues to rage on, garbage collection is now a standard component of many popular programming languages. For scenarios in which the garbage collector is negatively impacting performance, Java offers many options for tuning the garbage collector to improve its efficiency.
The Garbage Collection process is triggered by a variety of events that signal to the Garbage Collector that memory needs to be reclaimed.
Here are some common events that trigger Java Garbage Collection:
There are several ways to request the JVM to run Garbage Collector in a Java application:
System.gc()
method: Calling this method is the most common way to request Garbage Collection in a Java application. However, it does not guarantee that Garbage Collection will occur as it is only a suggestion to the JVM.
Runtime.getRuntime().gc()
method: This method provides another way to request Garbage Collection in a Java application. This method is similar to the System.gc()
method, and it also suggests that the JVM should run Garbage Collector, but again it does not guarantee that Garbage Collection will occur.
JConsole or VisualVM is a profiling tool that is included with the Java Development Kit. These tools provide a graphical user interface that allows developers to monitor the memory usage of their Java application in real-time. They also provide a way to request Garbage Collection on-demand by clicking a button.
The JVM can be configured with various command-line options to control Garbage Collection. For example, the -Xmx
option can be used to specify the maximum heap size, which can affect the frequency and duration of Garbage Collection events. The -XX:+DisableExplicitGC
option can be used to disable explicit calls to System.gc()
or Runtime.getRuntime().gc()
.
Heap dumps are snapshots of the Java heap that can be taken at any time during the application’s execution. They can be analyzed to identify memory leaks or other memory-related issues. Heap dumps can be requested using command-line options or profiling tools.
It is worth noting that requesting Garbage Collection too frequently can negatively impact the performance of the application. It is important to monitor the memory usage of the application and only request Garbage Collection when it is necessary. By using profiling tools and selecting appropriate Garbage Collection algorithms, developers can ensure that Garbage Collection is triggered in a way that minimizes the impact on the application’s performance.
For many simple applications, Java garbage collection is not something that a programmer needs to consciously consider. However, for programmers who want to advance their Java skills, it is important to understand how Java garbage collection works and the ways in which it can be tuned.
Besides the basic mechanisms of garbage collection, one of the most important points to understand about garbage collection in Java is that it is non-deterministic, and there is no way to predict when garbage collection will occur at run time. It is possible to include a hint in the code to run the garbage collector with the System.gc() or Runtime.getRuntime().gc() methods, but they provide no guarantee that the garbage collector will actually run.
The best approach to tuning Java garbage collection is setting flags on the JVM. Various flags such as the initial and maximum size of the heap, the size of the heap sections (e.g. Young Generation, Old Generation), can adjust the garbage collector to be used (e.g. Serial, G1, etc.). The nature of the application being tuned is a good initial guide to settings. For example, the Parallel garbage collector is efficient but will frequently cause “stop the world” events, making it better suited for backend processing where long pauses for garbage collection are acceptable.
On the other hand, the CMS garbage collector is designed to minimize pauses, making it ideal for GUI applications where responsiveness is important. Additional fine-tuning can be accomplished by changing the size of the heap or its sections and measuring garbage collection efficiency using a tool like jstat.
Try Stackify’s free code profiler, Prefix, to write better code on your workstation. Prefix works with .NET, Java, PHP, Node.js, Ruby, and Python.
Visit the following resources and tutorials for further reading on Java garbage collection:
If you would like to be a guest contributor to the Stackify blog please reach out to [email protected]