0

Java と JComboboxes に関する非常に奇妙な問題を解決するのを手伝ってくれる人がいるかもしれません。問題を追跡するために数時間試しましたが、解決策が見つかりません。ここに巨大なコードを貼り付けたくはありませんが、次の単純なループがそれを示しています。

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

このコードはどこでも実行できますが、1000 個の ComboBox は GC されず、理解できません。

4

3 に答える 3

3

JComboBox は、コンボボックスへのリスナーを持つ DefaultListModel を作成します。そのため、そのようなオブジェクト クラスタでのガベージ コレクションは延期されます。しかし、私と一緒に 4 回実行した後、ガベージが収集されたか、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());
}
于 2012-01-21T23:12:43.997 に答える
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. それを検索すると、この SO questionにつながります。あなたのステートメントでwhileループを使用して、JConsoleをメインメソッドに接続しようとしました。残念ながら、私のメイン プログラムはOutOfMemoryExceptionJConsole が接続する前に をスローしたため、trashgod が回答で行ったような素敵な画像を生成できませんでした。

于 2012-01-21T23:37:38.380 に答える
1
i can do this code where ever i wont the 1000 ComboBoxes are never GCed 
and i do not get it, why

答えは、このオブジェクトへの別の参照が存在しない場合、おそらく非常に単純なオブジェクトである可能性があります。または、別の問題は、静的オブジェクトから/へ参照したことが原因である可能性があります (決して GC で null 値を取ることはできません)。あなたのオブジェクトは静的です

于 2012-01-22T00:24:19.820 に答える