I am observing some inconsistent behaviour between OS and Java versions when calling JDialog.dispose to dispose a JDialog (also occurs for JFrame).
The simple sample application, below, can be used to demonstrate the problem. If you run it and profile the application you will notice that any JDialog instances created by clicking on the "New Dialog" and subsequently closed do not get garbage collected as they are still being referenced by instances of sun.lwawt.macosx.CPlatformWindow
, causing a memory leak in the application.
I don't believe this is due to any weak references either as I observed this problem in an environment that had experienced an OutOfMemoryError
, so I would expect that anything that could have been garbage collected would have been at that point.
The problem occurs in the following environments:
- Mac OS X 10.9: Java 1.7.0_5
- Mac OS X 10.9: Java 1.7.0_45
The problem does not occur in the following environments:
- Mac OS X 10.9: Java 1.6.0_65
- Windows 7: Java 1.7.0_45
In these environments the JDialog instances are promptly collected and (obviously) no longer visible in JProfiler.
Note: The problem occurs using DISPOSE_ON_CLOSE or handling the close manually as commented out in the sample.
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.*;
public class Testing extends JFrame {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
final JDialog parent = new JDialog((Frame)null, "Parent", false);
JButton add = new JButton("New Dialog");
add.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
final JDialog child = new JDialog(parent, "Child", false);
// child.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
child.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
child.setSize(100, 100);
//child.addWindowListener(new WindowAdapter() {
// @Override
// public void windowClosing(WindowEvent e) {
// child.setVisible(false);
// child.dispose();
// }
//});
child.setVisible(true);
}
});
parent.add(add);
parent.pack();
parent.setVisible(true);
}
});
}
}
Is there something that I am doing incorrectly?
Is my expected behaviour incorrect?
If not, can anyone point me to a Java bug report that covers this (I have had no luck finding one)?
Any suggested workarounds?