Следующее демонстрационное приложение создает JFrame с JInternalFrame (интерфейс MDI).Внутренняя рамка оснащена JTree с моделью JTree.Для имитации большой модели с моделью JTree связан буфер размером 10 МБ.Когда внутренний фрейм закрывается (удаляется), JTree и его модель никогда не будут собирать мусор.
jvisualvm показывает причину - некоторые статические поля класса Swing будут сохранять ссылки на JTree.В отличие от других утечек памяти Swing, здесь не используется обработчик событий.
Это ошибка?Есть ли чистое решение, собирающее расположенную внутреннюю рамку, ее дерево и его модель (помимо обходных путей, таких как использование слабых ссылок, аннулирование данных в модели JTree)?
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
public class Test extends javax.swing.JFrame {
public Test() {
javax.swing.JDesktopPane jDesktopPane = new javax.swing.JDesktopPane();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
setContentPane(jDesktopPane);
InternalTreeFrame f = new InternalTreeFrame();
jDesktopPane.add(f);
f.show();
pack();
setBounds(10, 10, 400, 300);
}
public class InternalTreeFrame extends javax.swing.JInternalFrame {
public InternalTreeFrame() {
javax.swing.JScrollPane jScrollPane = new javax.swing.JScrollPane();
javax.swing.JTree jTree = new javax.swing.JTree();
jScrollPane.setViewportView(jTree);
jTree.setModel(new DefaultTreeModel(new DefaultMutableTreeNode(new LargeObject("big root"))));
setContentPane(jScrollPane);
setClosable(true);
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
pack();
setBounds(10, 10, 300, 200);
}
}
// 10MB helper object, easy to spot in visual vm heap dump
public class LargeObject {
public LargeObject(String name) {
this.name = name;
buff = new byte[1024*1024*10];
}
@Override
public String toString() {
return name;
}
private final String name;
private final byte[] buff;
}
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new Test().setVisible(true);
}
});
}
}