JDialog никогда не собирает мусор - PullRequest
1 голос
/ 04 мая 2011

Почему следующий код никогда не собирает мусор для экземпляра JDialog?Экземпляр X не имеет ссылки, и диалоговое окно было удалено.

public class Test {

public static void main(String[] args) throws Throwable {
    test();

    Runtime.getRuntime().gc();
}

public static void test() throws Throwable {
    X x = new X();
    x.setVisible(true);
    x.dispose();
}

public static class X extends JDialog {

    public X() {
        super();
    }

    @Override
    protected void finalize() throws Throwable {
        System.out.println("destroyed !");
        super.finalize();
    }

}

}

Спасибо

Ответы [ 5 ]

2 голосов
/ 13 января 2012

Вопрос (и некоторые ответы на него) смешивают две вещи: сборку мусора и финализацию.Runtime.getRuntime (). Gc () - это просто подсказка, что коллекция должна быть запущена, и очень вероятно, что диалог был собран позже (гарантии до сих пор нет).Но это не значит, что финализатор запустится.Виртуальная машина будет избегать выполнения методов финализации настолько, насколько это возможно.

Есть еще одна проблема с вашей тестовой программой.JDialog без родителя заставляет Swing создать анонимный фрейм в качестве родителя за кулисами, который останется в живых с непредсказуемыми результатами (AWT работает в другом потоке).

Попробуйте эту тестовую программу:

import java.lang.ref.WeakReference;

import javax.swing.JDialog;
import javax.swing.JFrame;

public class Test {

public static void main(String[] args) throws Throwable {
    WeakReference<JDialog> ref = test();

    Runtime.getRuntime().gc();
    System.out.println(ref.get()==null? "collected": "still flying around");
  }

  public static WeakReference<JDialog> test() throws Throwable {
      JDialog d = new JDialog(new JFrame());
      WeakReference<JDialog> ref = new WeakReference<JDialog>(d);
      d.setVisible(true);
      d.dispose();
      d.getOwner().dispose();
      return ref;
  }
}

Это работает для меня.

Альтернатива Runtime.getRuntime (). Gc ():

try {
    byte[] b = new byte[Integer.MAX_VALUE];
} catch(OutOfMemoryError err) {}

, поскольку виртуальная машина гарантирует выполнение gc до OOME (может не работать с 64-битной версией).vms ;-)).

1 голос
/ 04 мая 2011

Как было сказано ранее - вы не можете ожидать GC в определенное время. Но вы можете «форсировать» его, заполняя память.

попробуйте этот код, он заполняет память после удаления вашего класса. Он выделяет много длинных в цикле, но любой больший класс будет лучше. (хотя этого достаточно по умолчанию)

public class Test {

    public static void main(String[] args) throws Throwable {
        test();

        Runtime.getRuntime().gc();
    }

    public static void test() throws Throwable {
        X x = new X();
        x.setVisible(true);
        x.dispose();
        //Fill memory:
        for (int i = 0; i < Integer.MAX_VALUE; ++i) {
            Long l = 10L;
        }
    }

    public static class X extends JDialog {

        public X() {
            super();
        }

        @Override
        protected void finalize() throws Throwable {
            System.out.println("destroyed !");
            super.finalize();
        }

    }

}
1 голос
/ 04 мая 2011

GC-звонки не могут ожидаться в определенное время.Он вызывается случайным образом или когда JVM выделяет полную память.

PS Ваш x.dispose(); не вызывает GC.Это может просто отметить, что этот объект можно собрать.

0 голосов
/ 04 мая 2011

JVM останавливается до запуска сборки мусора.Поэтому JDialog никогда не собирается сборщиком мусора и поэтому никогда не завершается.

0 голосов
/ 04 мая 2011

диалоговое окно, первое никогда не GC'ed, и есть некоторые ошибки с этим, но для ***, bugsParade теперь заморожен

dispose () не имеет ничего общего с GC http://download.oracle.com/javase/6/docs/api/java/awt/Window.html#dispose%28%29

...