An Important Java 6 Memory Leak You Should Know About

We’ve spent several days now with NetBeans 6, the SAP Memory Analyzer, and other tools trying to pinpoint some pretty bad memory leaks in one of our apps. One one particular set of screens, the tools kept pointing to a modalDialogs Vector in java.awt.Dialog.

Cockroach

We just now found this discussion, leading to bug 6497929 describing the problem.

This is marked fixed, but only for Java 7. I believe this is important and deserves to be fixed in Java 6. In the meantime, the comment from John F (on bug 6497929 report) describes a very reasonable workaround that you ought to know about.


6 Responses to “An Important Java 6 Memory Leak You Should Know About”

Dan Lewis Says:

As of 1.6.0_02, the field modalDialogs is declared in java.awt.Dialog like this:
transient static Vector modalDialogs = new Vector();

So, it’s package local. But wait, John F.’s workaround uses reflection like this:
Field f = java.awt.Dialog.class.getDeclaredField(”modalDialogs”);
f.setAccessible(true);

So does the f.setAccessible() call make it possible to violate the member visibility from outside the package? Or is it doing something else that I don’t understand.

Eric Burke Says:

Absolutely. setAccessible() lets you access private fields and methods. It is a wonderful thing that many frameworks take advantage of. If you are running with a SecurityManager installed, however, this can be prevented.

Dan Lewis Says:

Just when I think I know something about Java… BTW I wonder if this should be added to our project…we haven’t noticed this issue yet but maybe it’s because we are using -mx1024m. :( What is the perf. overhead of looking at every event like that? Is that the workaround you went with?

Eric Burke Says:

We just put in the fix today, but I’d think the performance overhead of a single event listener checking for window closing events is minimal…particularly compared to the huge memory leaks we just fixed.

studdugie Says:

You can improve the performance of the hack by simplifying the while loop.

Original:
while (modalDialogs.contains(dialog)) {
modalDialogs.remove(dialog);
}

Tweaked:
while (modalDialogs.remove(dialog));

Notice the dangling semicolon. It’s an empty loop body because all the work is done in the test. The difference between the two versions is the original scans the Vector 2x for each found Dialog object. The “tweaked” version only requires a single scan per matching dialog.

If you really want to get sick w/ it we can go a step further and explicitly synchronize modalDialogs. The reason we might consider doing this is because each iteration of the loop generates a single monitor enter/exit pair, in the tweaked version, and up to 2x pairs in the original. They are expensive operations, especially when the monitor is contended. So by explicitly synchronizing on modalDialogs we reduce the events to a single pair, regardless of the number of iterations. The technique is called lock coarsening. I only recommend doing this if you are running Java 5. The Hotspot compiler in Java 6 has the lock coarsening optimization baked right in.

Eric Burke Says:

It’s too bad this uses still uses Vector since it’s all thread-confined to the EDT anyway.

Leave a Reply