开发者

Java "dead" objects not being garbage collected

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 opera开发者_如何学运维tes. 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


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.


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.


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


  • 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).


The behaviour of the garbage collector is not fully specified. If a particular implementation choose not to collect certain objects, it is allowed to do so. This could be done to avoid spending large periods of time in the garbage collector, which could have detrimental effects to the operation of the application.


Imagine you had a collection which contained millions of small objects, most of which were not referenced anywhere else. If the only references to that collection was cleared, would you want the GC to spend a long time cleaning out those millions of small objects, or would you want it to do so over the course of several calls? In most cases, the latter would be better for the application.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜