Object Life Cycle:
The heap is divided into two generations, young and tenured. Young consists of Eden, two Survivor spaces, and a Virtual space. Most of the objects that are created are initially allocated in Eden. After that, live objects are moved to a single Survivor space, while the other one is cleared of objects that became garbage. After that process is finished, the Survivor spaces are swapped, with all live objects copied from one to another and garbage cleaned. This process is called minor collection. After some cycles of minor collection, still living objects are moved into tenured generation. Eventually, the tenured generation is filled up and also needs to be cleaned. The process of garbage collection in the entire heap, including the tenured generation is called major collection, and happens less often than minor collections.
Now, we understand how the garbage collection is organized, but how to efficiently determine if an object is a live object or not?
In order to do so, GC builds several object trees with roots of the trees being objects that can be reached from the application.
Examples of such objects are:
Examples of such objects are:
- Local variables in the stack of the thread.
- Active Java threads
- Static variables.
So after building object trees the GC will have the objects divided into reachable, and, therefore, live objects, and non-reachable objects, or garbage.
Now it should be clearer why resource leaks are very dangerous - imagine a socket or a JDBC connection that has not been properly closed - the garbage collector will find it to be reachable and not collect it, taking away resources from your application.
So, let’s move on to the actual object lifecycle in Java.
1. Created - memory was allocated, object placed in Eden;
2. Initialized - object is initialized with a value and becomes ready to be used;
3. In use - object is used for some period of time, until no references to it remain;
4. Unreachable - after there are no references to the object it enters this state, and can be collected by the GC;
5. Finalized - object is garbage collected and memory it occupied is freed up.
But that is not the most fine-grained view one can take. There exist several types of references in java.lang.ref package and they differ in how GC treats them.
· Strong reference - that is what is generally just named reference, meaning that some other object has a reference to it.
· Soft reference - the GC will try to preserve object with only soft references to it as long as possible, but the object will be garbage collected if there is imminent danger of an OutOfMemory error.
· Weak reference - this is weaker than soft reference, as the GC will collect this object at any time. Typically used for storing object reference is such a way so it will still be collected if all other references disappear.
· Phantom reference - this reference also does not save an object from garbage collection, but adds an option to “access” object state after it has already been collected.
The improved diagram with different reference types.
Turns out, object lifecycle is not as simple as it is generally regarded in Java. While this answer still does not reflect many finer aspects of working with GC and object lifecycle, I hope it provides a good overview of how to think about memory allocation in Java.