Утечка памяти в JCombobox, даже если на нее вообще нет ссылок? - PullRequest
0 голосов
/ 22 января 2012

Может быть, некоторые из вас могут помочь мне решить очень странную проблему с java и JComboboxes.Я несколько часов пытался отследить проблему, но не могу найти решение.Я не хочу вставлять здесь огромный код, но этот простой цикл демонстрирует это:

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

Я могу запустить этот код где угодно, 1000 ComboBox никогда не GCed, и я не понимаю, почему???

Ответы [ 3 ]

3 голосов
/ 22 января 2012

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());
}
2 голосов
/ 22 января 2012

Я пытался с помощью простого тестового примера, используя метод 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");
      }
    } );
  }
}

, приводящий к следующей трассировке на моем Macработает с JDK1.6

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)

Так что да, на моей машине я бы пришел к выводу, что JComboBox все еще присутствует в памяти через ссылку в AppContext.Поиск этого ведет нас к этому ТАКОМУ вопросу .Я попытался подключить JConsole к методу main с помощью цикла while с вашим оператором.К сожалению, моя основная программа выдавала OutOfMemoryException до того, как JConsole смог подключиться, поэтому я не смог сгенерировать красивую картинку, как trashgod в своем ответе.

1 голос
/ 22 января 2012
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 может толькопринять нулевое значение), или ваши объекты являются статическими

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...