开发者

Java Swing JTree is not garbage collected

开发者 https://www.devze.com 2023-02-01 02:54 出处:网络
The following demo app creates a JFrame with a JInternalFrame (MDI interface). The internal frame features a JTree, with a JTree model. To simulate a large model, a 10MB buffer is associated to the JT

The following demo app creates a JFrame with a JInternalFrame (MDI interface). The internal frame features a JTree, with a JTree model. To simulate a large model, a 10MB buffer is associated to the JTree model. When the internal frame is closed (disposed), the JTree and its model will never be garbage collected.

jvisualvm shows the reason -- some static Swing class fields will keep references to the JTree. Unlike other Swing memory leaks no event handler is used here.

Is this a bug? Is there a clean solution collecting the disposed internal frame, its tree and its model (besides workarounds like using weak references, nullifying the data in the JTree model)?

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);
  }
      });
   }
}


Not sure if this is a bug, but a solution would be to set an empty model into the JTree in the windowClosing() event of the (internal) frame


There is a known bug in the JDK about the last JInternalFrame not being garbage collected correctly on dispose. This is because the JDesktopPane maintains a framesCache which holds references to the JInternalFrames. This cache is not refreshed when the last JInternalFrame is closed.

The workaround is to force the cache to reload by calling JDesktopPane.selectFrame, as shown below:

    f.addInternalFrameListener(new InternalFrameAdapter() {
        public void internalFrameClosed(InternalFrameEvent e) {
            jDesktopPane.selectFrame(true);
        }
    });

Try it out and you will see memory reclaimed once the JInternalFrame is closed.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号