2010-12-23 48 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