我在调用 JDialog.dispose 来处理 JDialog 时观察到操作系统和 Java 版本之间存在一些不一致的行为(对于 JFrame 也会发生)。
下面的简单示例应用程序可用于演示该问题。如果您运行它并对应用程序进行概要分析,您会注意到通过单击“新建对话框”创建并随后关闭的任何 JDialog 实例都不会被垃圾收集,因为它们仍在被 sun.lwawt.macosx 的实例引用。 CPlatformWindow
,导致应用程序内存泄漏。
我不认为这是由于任何弱引用造成的,因为我在经历过 OutOfMemoryError
的环境中观察到这个问题,所以我希望任何可以被垃圾收集的东西都会一直在那个时候。
问题出现在以下环境中:
- Mac OS X 10.9:Java 1.7.0_5
- Mac OS X 10.9:Java 1.7.0_45
该问题不会出现在以下环境中:
- Mac OS X 10.9:Java 1.6.0_65
- Windows 7:Java 1.7.0_45
在这些环境中,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 错误报告(我没有找到一个)?
有任何建议的解决方法吗?
最佳答案
我看到了同样的事情,并且能够通过覆盖我窗口上的 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 但总比没有好,应该对您有所帮助。
关于java - Mac OS Java 7 JDialog.dispose 内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19781877/