在调用JDialog.dispose来处理JDialog时,我观察到操作系统和Java版本之间存在一些不一致的行为(也适用于JFrame)。
下面的简单示例应用程序可用于演示此问题。如果您运行它并对应用程序进行概要分析,您会注意到通过单击“新建对话框”创建并随后关闭的任何JDialog实例都不会被垃圾收集,因为它们仍然被sun.lwawt.macosx.CPlatformWindow
的实例引用,从而导致内存泄漏应用程序。
我不相信这是由于任何弱引用,因为我在经历过OutOfMemoryError
的环境中观察到这个问题,所以我希望任何可能被垃圾收集的东西都是在那一点。
在以下环境中出现问题:
在以下环境中出现不问题:
在这些环境中,JDialog实例被迅速收集,并且(显然)在JProfiler中不再可见。
注意:使用DISPOSE_ON_CLOSE或在示例中注释掉手动处理关闭时会出现问题。
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);
}
});
}
}
我做错了吗?
我的预期行为是否不正确?
如果没有,是否有人可以向我指出一个涵盖此问题的Java错误报告(我找不到运气)?
任何建议的解决方法?
答案 0 :(得分:2)
我看到同样的事情并且能够通过覆盖我窗口上的dispose方法来释放窗口,如下所示:
@SuppressWarnings("deprecation")
@Override
public void dispose()
{
ComponentPeer peer = getPeer();
super.dispose();
if (null != peer)
{
try
{
Class<?> peerClass = Class.forName("sun.lwawt.LWComponentPeer");
Field targetField = peerClass.getDeclaredField("target");
targetField.setAccessible(true);
targetField.set(peer, null);
Field windowField = peer.getClass().getDeclaredField("platformWindow");
windowField.setAccessible(true);
Object platformWindow = windowField.get(peer);
targetField = platformWindow.getClass().getDeclaredField("target");
targetField.setAccessible(true);
targetField.set(platformWindow, null);
Field componentField = peerClass.getDeclaredField("platformComponent");
componentField.setAccessible(true);
Object platformComponent = componentField.get(peer);
targetField = platformComponent.getClass().getDeclaredField("target");
targetField.setAccessible(true);
targetField.set(platformComponent, null);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
这并没有发布CPlatformWindow,但它总比没有好,应该帮助你。