【问题标题】:JCombobox memory leaking even if not referenced at all?即使根本没有引用 JCombobox 内存泄漏?
【发布时间】:2012-01-21 22:51:12
【问题描述】:

也许你们中的一些人可以帮助我解决一个关于 java 和 JComboboxes 的非常奇怪的问题。我尝试了几个小时来追查问题,但我找不到解决方案。我不想在这里粘贴大量代码,但这个简单的循环演示了它:

    JComboBox cb;
    for(int i=0;i<1000;i++)
    {
        cb=new JComboBox();
    }

我可以在任何我想要的地方运行这段代码,1000 个 ComboBox 永远不会被 GC,我不明白,为什么???

【问题讨论】:

  • 内存不足了吗?否则 GC 可能只是决定不清理任何东西......
  • 不,不在这个示例中,但在我使用它的巨大应用程序中,我遇到了 GC,但我尝试了这个简单的代码,它适用于所有(按钮、表格等......)但不是与组合框。尝试了 100000,但内存不足:-(
  • 对于报告的 jcombobox 内存泄漏,google for 'site:bugs.sun.com jcombobox memory leak',但首先通过循环运行示例,直到内存不足,以确保它是内存泄漏。
  • 我很好奇为什么你需要测试这个问题的原因
  • 随着时间的推移,您可以尝试分析您的示例,如 here 所示。

标签: java swing memory-leaks jcombobox garbage


【解决方案1】:

JComboBox 创建一个 DefaultListModel 并带有一个组合框的侦听器。所以在这样一个对象集群上的垃圾收集被推迟了。然而,在与我一起运行第四次之后,要么垃圾被收集,要么 JIT 发现它不需要创建这些对象。

也许你的问题是显式调用System.gc() 没有清理它?我可以想象。


*如何追踪问题

我尝试了以下排除组件。

private static class ReducedJComboBox<T> extends JComboBox<T> {

    @Override
    public void setEditor(ComboBoxEditor anEditor) {
    }

}

public static void main( String[] args )
{
    System.out.println("; " + Runtime.getRuntime().freeMemory());
    long t0 = System.currentTimeMillis();
    ComboBoxModel model = new DefaultComboBoxModel();
    ComboBoxEditor editor = new ComboBoxEditor() {

        public Component getEditorComponent() {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        public void setItem(Object anObject) {
        }

        public Object getItem() {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        public void selectAll() {
        }

        public void addActionListener(ActionListener l) {
        }

        public void removeActionListener(ActionListener l) {
        }
    };
    JComboBox cb;
    for (int i = 0; i < 1000; i++) {
        cb = new JComboBox();
        cb.setModel(model);
        cb.setEditable(false);
        cb.setEditor(editor);
    }
    long dt = t0 - System.currentTimeMillis();
    System.out.println("dt=" + dt + " ms; " + Runtime.getRuntime().freeMemory());
    System.gc();
    System.out.println("finally " + Runtime.getRuntime().freeMemory());
}

【讨论】:

  • 尝试使用手动 gc() 但没有帮助。也许 ComboBox 在内部使用 ComboBox 的多个组件在内部创建了一些奇怪的引用。
【解决方案2】:

我使用NBTestCase#assertGC 方法尝试了一个简单的测试用例。这种方法的好处是在内存泄漏的情况下打印出对您正在检查的对象的强引用。它还通过用哑字节数组填充堆来触发 GC,从而强制 GC 启动。

我使用的非常简单的测试用例

public class ComboBoxMemoryLeak {

  public static void main( String[] args ) {
    EventQueue.invokeLater( new Runnable() {
      @Override
      public void run() {
        List<WeakReference<JComboBox>> references = new ArrayList<WeakReference<JComboBox>>(  );
        JComboBox comboBox;
        for (int i = 0; i < 1000; i++ ){
          comboBox = new JComboBox(  );
          references.add( new WeakReference<JComboBox>( comboBox ) );
        }
        comboBox = null;
        for ( int i = 0, referencesSize = references.size(); i < referencesSize; i++ ) {
          System.out.println( "i = " + i );
          WeakReference<JComboBox> weakReference = references.get( i );
          NbTestCase.assertGC( "Combobox", weakReference );
        }
        System.out.println("No memory leak found");
      }
    } );
  }
}

在运行 JDK1.6 的 Mac 上导致以下跟踪

i = 0
Exception in thread "AWT-EventQueue-0" junit.framework.AssertionFailedError: Combobox:
private static sun.awt.AppContext sun.awt.AppContext.mainAppContext->
sun.awt.AppContext@30f7f540-table->
java.util.HashMap@c324b85-table->
[Ljava.util.HashMap$Entry;@770fba26-[8]->
java.util.HashMap$Entry@63adf08f-value->
java.beans.PropertyChangeSupport@4f1b8540-children->
java.util.Hashtable@2305454a-table->
[Ljava.util.Hashtable$Entry;@4a9a4ba3-[0]->
java.util.Hashtable$Entry@6aed0f19-value->
java.beans.PropertyChangeSupport@23597cac-listeners->
sun.awt.EventListenerAggregate@2f39c244-listenerList->
[Ljava.beans.PropertyChangeListener;@2e2e06bd-[0]->
javax.swing.JViewport$1@2a72cf60-this$0->
javax.swing.JViewport@2b9c1dc4-parent->
javax.swing.JScrollPane@b99f7c6-parent->
com.apple.laf.AquaComboBoxPopup@6699166f-comboBox->
javax.swing.JComboBox@3bc634b9
    at junit.framework.Assert.fail(Assert.java:50)
    at org.netbeans.junit.NbTestCase$4.run(NbTestCase.java:1351)
    at org.netbeans.junit.internal.NbModuleLogHandler.whileIgnoringOOME(NbModuleLogHandler.java:143)
    at org.netbeans.junit.NbTestCase.assertGC(NbTestCase.java:1309)
    at org.netbeans.junit.NbTestCase.assertGC(NbTestCase.java:1285)
    at ComboBoxMemoryLeak$1.run(ComboBoxMemoryLeak.java:32)
    at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209)
    at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:677)
    at java.awt.EventQueue.access$000(EventQueue.java:85)
    at java.awt.EventQueue$1.run(EventQueue.java:638)
    at java.awt.EventQueue$1.run(EventQueue.java:636)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:87)
    at java.awt.EventQueue.dispatchEvent(EventQueue.java:647)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:296)
    at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:211)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:201)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:196)
    at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:188)
    at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)

所以是的,在我的机器上,我会通过AppContext 中的引用得出结论,JComboBox 仍然存在于内存中。搜索将我们带到this SO question。我尝试使用您的语句将 JConsole 连接到一个带有 while 循环的 main 方法。不幸的是,我的主程序在 JConsole 连接之前抛出了一个OutOfMemoryException,所以我无法像垃圾神在他的回答中那样生成一张漂亮的图片。

【讨论】:

  • 检查组合框的弱引用是一个很好的解决方案。
【解决方案3】:
i can do this code where ever i wont the 1000 ComboBoxes are never GCed 
and i do not get it, why

答案可能很简单,如果不存在对该对象的另一个引用,则该对象可能会被 GC'ed,或者另一个问题可能是您从/向静态对象引用(从不 GC'ed 只能取 null 值),或者你的对象是静态的

【讨论】:

  • 我没有引用创建的对象。也许摇摆在里面保留了一些
  • 虽然让 assertGC 通过,但它是一个方便的工具。当您将每个具有违规引用的对象清空时,不幸的是,您最终可能会清空五个不同的项目。我什至用 assertGC 测试了 JPanel,我最终得到了导致测试失败的库。我想出了一个解决方案来解决这个问题,但它很难看,我不得不使用反射......
  • @Mark Ba​​sler JComboBox 及其派生的 JList 在删除超过 999 个项目的情况下存在性能问题,我不知道为什么、什么、在哪里、如何......
  • 是的,我在使用 JComboBox、JSplitPane 和 JPanels 时遇到了同样的问题。也与听众一起。这些是 Java 的老问题,已经存在 15 年了。
猜你喜欢
  • 1970-01-01
  • 2021-07-20
  • 2013-04-30
  • 1970-01-01
  • 1970-01-01
  • 2017-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多