Java Swing JTree не является сборщиком мусора - PullRequest
2 голосов
/ 23 декабря 2010

Следующее демонстрационное приложение создает 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);
  }
      });
   }
}

Ответы [ 2 ]

1 голос
/ 23 декабря 2010

В JDK есть известная ошибка о том, что последний JInternalFrame не был правильно собран мусором на dispose.Это потому, что JDesktopPane поддерживает framesCache, который содержит ссылки на JInternalFrames.Этот кэш не обновляется при закрытии последнего JInternalFrame.

Обходной путь - принудительно перезагрузить кэш, вызывая JDesktopPane.selectFrame, как показано ниже:вы увидите, что память будет восстановлена ​​после закрытия JInternalFrame.

1 голос
/ 23 декабря 2010

Не уверен, что это ошибка, но решением было бы установить пустую модель в JTree в событии windowClosing () (внутреннего) фрейма

...