Garbage Collection is basically the process of allocation and de allocation of memory space for objects. In the case of Java, it is handled by the JVM itself, and the developer need not worry about writing the code for it, unlike C or C++. To understand how Garbage Collection works in Java, we need to understand certain basic features of JVM, Memory Management.
JVM or Java Virtual Machine is basically an abstract computing machine, that translates the code into the machine language, which in turn enables the programs to be platform independent. Each JVM implementation could vary in the way Garbage Collection is implemented. Oracle previously had Rockit JVM, and after it took over Sun, it uses the Hotspot JVM in addition to Rockit.
Now if we take a look at the standard Hotspot JVM architecture, we see there are two main components related to Garbage collection. The Garbage collector itself and the heap memory. Basically heap is where all the objects are stored at run time, while Stack contains the local variables and references to the object. Once an object is not referenced any more, it is evicted from the heap memory. What essentially happens in Garbage Collection is that objects are evicted from heap and the space is reclaimed.
Now if we take Heap Memory, there are 3 major areas, as seen in the above diagram- Young Generation, Old Generation and Permanent Generation.
Now when we take the Young Generation, it is further sub divided into 3 regions.
Eden- Space where any object enters the runtime memory area.
S0 Survivor Space- Objects are moved from Eden to S0, and similiarly from S0 to S1 Survivor Space.
Objects in Survivor Space are moved to Tenured region, while Permanent Generation contains meta information of the classes, methods. However this Perm Gen space is removed in Java 8.
Now let us take a look at how the Garbage Collection process actually works. Every new object that is created is first stored in the Eden space in young generation of Heap Memory Area.
Now when the Minor Garbage Collection begins, all live objects( those that are still referenced) are moved from Eden to S0. And similarly all live objects in S0 are moved to S1. Basically all the live objects here are set aside. Those objects which are not live( not referenced) are the ones marked for garbage collection. Depending on the kind of garbage collector, the marked objects will be removed in one go or it will be carried in a separate process.
Now coming to Old Generation, all live objects in S1 are promoted to old generation space. And the dereferenced objects in S1 are marked for garbage collection. This is the last phase in instance life cycle with respect to Java GC. Here begins the Major Garbage Collection, that scans the old generation part of heap and marks all the dereferenced instances here.
So what happens is once all the de-referenced instances are removed from the heap memory, the location becomes empty and available for future objects. These blank spaces are fragmented by default, across the memory area, and it’s advisable to go for defragmentation for quicker memory allocation. Again based on the type of Garbage Collector, reclaimed memory will either be compacted dynamically or in a separate phase of GC.
Just before an object is removed from memory, Java GC, invokes the finalize() method of respective instance to free up any resources held by it. There is no specific order or time here in invoking finalize, before freeing up memory. The garbage collection is done by a daemon thread.
When is an object eligible for garbage collection?
Basically Java has different references for an object that determine the eligibility for removal.
Strong Reference- Not eligible for Garbage Collection
Soft Reference- Garbage collection possible, but only as a last option.
Weak and Phantom Reference indicates Garbage Collection is possible.
The compiler can choose to free objects earlier in an application if it sees no use for them in future. For eg an object created in a method, and used by that only, can be freed by compiler by setting it’s value to null. This is often used for optimization. There could be an added complexity, if the object has properties in the register and there is every chance that those values could be used in future. But still the instance would be marked for garbage collection.