Java “dead” objects not being garbage collected

garbage-collectionjavamemory-leaks

I know that during garbage collection in Java, objects that don't have any more references to them are marked as "dead" so that they can be deleted from memory by the garbage collector.

My question is if, during a garbage collection phase, all of the "dead" objects get deleted from memory or some of them survive? Why would a "dead" object survive a garbage collection phase?

LATER EDIT

Thank you for all of your answers. I can deduce that the main reason why "dead" objects would not be deleted is due to timing or spacing limitations of the way the Garbage Collector operates.
However, supposing that the Garbage Collector can reach all of the "dead" objects, I was wondering if there is a way to declare, reference, use, dereference, etc.. an object such that somehow it would skip the deletion phase even though it is "dead". I was thinking maybe objects belonging to classes which have static methods or inner classes or something like that may be kept in memory for some reason, even though they have no references to them.
Is such a scenario possible?

Thank you

Best Answer

My question is if, during a garbage collection phase, all of the "dead" objects get deleted from memory or some of them survive? Why would a "dead" object survive a garbage collection phase?

All current HotSpot GCs are generational collectors. Quoting from Wikipedia:

"It has been empirically observed that in many programs, the most recently created objects are also those most likely to become unreachable quickly (known as infant mortality or the generational hypothesis). A generational GC (also known as ephemeral GC) divides objects into generations and, on most cycles, will place only the objects of a subset of generations into the initial white (condemned) set. Furthermore, the runtime system maintains knowledge of when references cross generations by observing the creation and overwriting of references. When the garbage collector runs, it may be able to use this knowledge to prove that some objects in the initial white set are unreachable without having to traverse the entire reference tree. If the generational hypothesis holds, this results in much faster collection cycles while still reclaiming most unreachable objects."

What this means for your question is that most GC cycles collect only garbage objects in young generations. A garbage object in the oldest generation can survive multiple GC cycles ... until the old generation is finally collected. (And in the new G1 GC, apparently the old generation is collected a bit at a time ... which can delay reclamation even further.)

Other causes for (notionally) unreachable objects to survive include:

  • Unreachable objects with (unexecuted) finalizers are attached to a finalization queue by the garbage collector for processing after the GC has finished.

  • Objects that are softly, weakly or phantom referenced are actually still reachable, and are handled by their respective reference queue managers after the GC has finished.

  • Objects that are reachable by virtue of JNI global references, etcetera. (thanks @bestss)

  • Various hidden references exist that relate instances, their classes and their classloaders.

  • There is a hidden reference from an inner instance to its outer instance.

  • There is a hidden reference from a class to the intern'd String objects that represent its string literals.

However, these are all consequences of the definition of reachability:

"A reachable object is any object that can be accessed in any potential continuing computation from any live thread." - JLS 12.6.1

It is also worth noting that the rules for the GC have an element of conservativeness about them. They say that a reachable object won't be deleted, but they don't say that an object that is (strictly) unreachable will be deleted. This allows for cases where an object cannot be accessed but the runtime system is unable to figure that out.


Your followup question:

However, supposing that the Garbage Collector can reach all of the "dead" objects, I was wondering if there is a way to declare, reference, use, dereference, etc.. an object such that somehow it would skip the deletion phase even though it is "dead".

"Dead" is not a well-defined term. If the garbage collector can reach the objects, they are by definition reachable. They will not be deleted while they are still reachable.

If they are both dead AND reachable (whatever "dead" means!) then the fact that they are reachable means they won't be deleted.

What you are proposing doesn't make sense.

I was thinking maybe objects belonging to classes which have static methods or inner classes or something like that may be kept in memory for some reason, even though they have no references to them. Is such a scenario possible?

Static methods don't have references ... unless they happen to be on the call stack. Then the local variables may contain references just like any other method call. Normal reachability rules apply.

Static fields are GC roots, for as long as the class itself exists. Normal reachability rules apply.

Instances of inner classes are no different to instance of other classes from a GC perspective. There can be a reference to an outer class instance in an inner class instance, but that leads to normal reachability.

In summary, there are some unexpected "causes" for reachability, but they are all a logical consequence of the definition of reachability.