Garbage Collection is a great mechanism that boosts an application's performance, and a good knowledge of this can help boost the developer productivity for application developers writing programs using the Java Programming Language. In this article, we will explore Garbage Collection techniques in Java.
In programming languages like Java where you write programs that are executed in managed environments, you are not allowed to access the system's memory directly. In Java, when you write your program and compile it using the Javac compiler, the program can be executed only inside the context of the Java Virtual Machine (JVM ). Similarly, when you write your program in C# and compile it, you are restricted to execute it within the context of the Common Language Runtime (CLR) environment.
Note that JVM and CLR are both virtual machines. The programs written in Java or C#, when compiled, generate intermediate code (known as Bytecode in Java and IL code in C#). Such compiled codes contain operation codes (op codes) that can be understood by these virtual machines (JVM or CLR, depending on whether you have compiled your program in Java or C#) only.
What is Garbage Collection? Why Is It Needed?
Garbage Collection is the process of knowing which objects are cleaned up automatically when they are no longer needed. Garbage Collection (GC) is a process that can release memory that is no longer referenced by any reachable Java object. Note that you can invoke the garbage collector by making a call to the System.gc() method. However, this doesn't guarantee that the garbage collector would be called immediately. Neither does it guarantee that the garbage collector will be triggered to perform a garbage collection. The runtime decides whether it is safe to invoke the garbage collector; to do this, it checks if the active threads of the running application are at a safe point for the garbage collector to be executed.
How Does It Work?
Essentially, the JVM provides support for two strategies in garbage collection. These are:
- Reference counting
Reference counting is a strategy in which the Java runtime keeps track of the reference count of each object. As soon as a new object is created, the reference count is set to 1. From then on, when the object is referenced, the reference count is increased. At any given point in time, if the reference count of an object becomes zero, the object is a garbage object and the memory space occupied by the object is available for clean-up. This strategy works well if the number of objects in your application is not that high. On the contrary, if your application creates many objects, maintaining the reference counts of so many objects is a challenge.
Tracing collectors are those that iteratively trace all references starting from the root object. The root object is located by analysing the registers, global fields, and stack frames for the executing method. Tracing collectors can handle circular structures (unlike reference-counting collectors) and are widely used for reclaiming memory in programs written by using dynamic languages.
But, Wait; How Do I Write Better Code?
You, as the developer, should keep in mind that it all depends on what code you write for the garbage collector to work properly. In the newer versions of JVM, you have all the ingredients. Now it's your turn to cook the food with care. Let me tell you a few important points here.
You should avoid creating objects that are long lived. You should prefer to create local objects instead; as such, objects would be cleaned up more frequently by the garbage collector. You should set object references to null once they are no longer needed and especially if there are long running operations succeeding the point at which you set the object instance to null. It should be noted that objects that have finalizers have significant overhead compared to objects that don't have finalizers; you should create objects with finalizers only when it is absolutely needed. There are many more points; you should keep one thing in mind and that is you, as a developer, should write code that facilitates garbage collection to make your application high performant. That's all.
Over the past few years, garbage collection has come a long way; newer versions of JVM have come up and have been optimized a lot. Now, the JVMs offer you much better performance—fast allocation and shorter garbage collection pauses. You, as a developer, should have a good knowledge of how a garbage collector works and you should be able to write programs that can leverage the features offered by the newer versions of JVM so that, together with the optimized JVM at hand, you can write programs where the cost of object allocation and garbage collection can be reduced considerably. Happy reading!