Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Impossible Java memory references in Heap Dump

I have a Java Heap Dump taken at 7:41pm which I am analysing with Eclipse Memory Analysis Tool. The heap dump includes 20 session objects.

Using the Path to GC Roots command on one of these session objects in my heap shows the following 3 references to the session object.

  • A finalizer reference from the "unfinalized" linked list owned by the Finalizer thread. My object is 3rd in line to be finalized.
  • A strong reference to the session object from a message handler thread which is itself referenced from a cleanup TimerTask scheduled to run at 7:11pm.
  • A weak reference to the session object from a WeakHashMap$Entry. The WeakHashMap is kept alive by a static strong reference.

How can the session object be on the finalizer queue when it still has a strong and a weak reference?

Of the remaining 19 session objects, 1 more is in the finalizer queue and has a similar weak reference. All the other 18 session objects are only weakly referenced. Why hasn't the GC cleared these weak refs?

A few general points:

  • Objects are only eligible for finalization AFTER their weak refs have been cleared (http://download.oracle.com/javase/6/docs/api/java/lang/ref/package-summary.html)
  • The session object does not have a finalizer which could resurrect it and even if it did it couldn't have been run while the object is still in the unfinalized queue behind other objects.
  • My application doesn't use Phantom refs which are the only refs which should be able to exist once an object is eligible for finalization. Even if my app did use phantom refs these objects do not expose their reference to the object they hold.
like image 458
mchr Avatar asked Dec 28 '22 02:12

mchr


1 Answers

I think the mistake you're making here is in this part:

A finalizer reference from the "unfinalized" linked list owned by the Finalizer thread. My object is 3rd in line to be finalized.

If you're talking about this:

static private Finalizer unfinalized = null;

in Sun's Finalizer.java (a Finalizer contains a next and prev Finalizer, hence the 'linked list' part, for those playing along at home), then that's not the list of things to be finalized.

Finalizer.add() is not (as I think you're assuming) called during the finalization process, when the object is unreachable; rather, that method is called at creation time of the Object (e.g. during <init>, by native code, for any Object which overrides finalize().

The presence of a Finalizer in the next chain doesn't mean it's about to be finalized; it's the

static private ReferenceQueue queue

which holds such objects. Being in the linked list just means that it has a finalize() method.

Therefore your first point is a red herring, it's your second point that's keeping the item reachable, and the third point flows from the second (because the WeakReference won't be cleared while the object is reachable).

Hope this helps!

like image 187
Cowan Avatar answered Dec 30 '22 16:12

Cowan