Java "dead" objects not being garbage collected

12,482

Solution 1

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.

Solution 2

One potential explanation for an unreachable object not being collected is time. As of Java 1.5 the amount of time the JVM spends garbage collecting can be limited using on of the following options...

  • -XX:MaxGCPauseMillis
  • -XX:GCTimeRatio=<nnn>

Both options are explained in detail here

Solution 3

As the System.gc() javadoc says

When control returns from the method call, the Java Virtual Machine has made a best effort to reclaim space from all discarded objects.

From which you can infer that a call to the garbage collector does not insure that all unused object will be reclaimed. As the garbage collection can completely differ between implementation, no definitive answer can be given. There is even java implementations without any garbage collection.

Solution 4

  • There are dead objects in "young" generation and there are dead objects in "old" generation. If GC being performed in "minor GC", only dead objects from young generation will be collected.
  • Additionally, you can use finalize() method to stop VM from collecting your object by throwing exception from finalize() (at least, this is how I understand Object.finalize() javadoc: Any exception thrown by the finalize method causes the finalization of this object to be halted, but is otherwise ignored).
Share:
12,482
Victor Blaga
Author by

Victor Blaga

Updated on June 05, 2022

Comments

  • Victor Blaga
    Victor Blaga about 2 years

    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