2010-12-23 56 views
2

下面的演示应用程序使用JInternalFrame(MDI接口)创建JFrame。内部框架具有JTree模型和JTree模型。为了模拟一个大型模型,一个10MB缓冲区与JTree模型相关联。当内部框架关闭(处置)时,JTree及其模型将永远不会被垃圾收集。Java Swing 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); 
    } 
     }); 
    } 
} 

回答

1

不知道这是一个错误,但是一个解决办法是设置一个空模式进入JTree的在(内部)帧

+0

谢谢!是的,这种解决方法实际上是我目前使用的。我实现了一个自定义的dispose()方法,该方法调用super.dispose()并将引用放入树模型中的大数据项。我刚才问自己,如果有更清晰的方法来解决这个问题的话。 – FreeJack 2010-12-23 12:42:50

1

的的windowClosing()事件中有公知的bug关于最后的JInternalFrame的JDK没有在dispose上被正确地垃圾收集。这是因为JDesktopPane维护一个framesCache它保存对JInternalFrames的引用。当最后一个JInternalFrame关闭时,此缓存不会刷新。

解决方法是强制高速缓存调用JDesktopPane.selectFrame重新加载,如下图所示:

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

试试吧,你会看到,一旦JInternalFrame处于关闭内存回收。

+0

谢谢,我已经试过了。首先,我修改了测试用例以创建10个内部框架。关闭所有这些,我看到两个没有回收的TreeModel实例。一个来自JDesktopPane的framesCache,另一个来自CompositionAreaHandler中的静态字段。使用缓存重新加载方法,由framesCache引用的实例将被回收,但另一个仍然存在。 – FreeJack 2010-12-23 12:36:03