Почему объект JFrame кажется живым, хотя на него нет ссылок? - PullRequest
2 голосов
/ 02 апреля 2020

Если я правильно помню, в Java можно написать

new JFrame();

без сохранения ссылки JFrame в любой переменной. Эта программа отобразит на экране окно GUI и оставит его открытым, пока программа не закроется. (Пожалуйста, исправьте меня, если это предположение неверно).

Теоретически, мы могли бы подумать, что, поскольку JFrame теперь недоступен из пользовательского кода, G C должен в какой-то момент освободить объект. И в результате связанные ресурсы ОС (окно GUI и т. Д. c) также будут освобождены.

Однако, если я правильно понимаю - эта программа является действующей и работающей * Программа 1051 * (хотя и довольно бесполезная), и она не взломает sh и не будет вести себя странным образом в любой момент (снова исправьте меня, если это предположение неверно).

Кажется, что G C не будет собирать объект JFrame, даже если на него нет никаких ссылок, или, по крайней мере, это не приведет к освобождению связанных ресурсов ОС.

Я хотел бы понять: как это возможно?

  1. Сохраняет ли конструктор JFrame this где-нибудь, чтобы его нельзя было собрать? В исходном коде для суперкласса JFrame java .awt.Frame (метод noteFrame) кадр кажется сохраненным в очереди слабых ссылок. Но так как это слабые ссылки, это, кажется, не объясняет вещи

  2. Действительно ли так, что G C действительно в конечном итоге освобождает JFrame - однако метод финализатора JFrame не не освобождает связанные ресурсы ОС, поэтому окно GUI остается открытым?

  3. Любое другое объяснение?

Обратите внимание, что это дополнительный вопрос к более теоретическому вопросу, который я разместил на SE.SE . Этот вопрос отличается тем, что относится конкретно к деталям реализации Java.

1 Ответ

3 голосов
/ 02 апреля 2020

A JFrame, который создается только через new JFrame() без каких-либо дополнительных действий, не будет открыт на экране и не помешает сборке мусора. Только реализация, подключенная к устройству отображения, будет ссылаться из реализации AWT и не сможет собирать мусор до тех пор, пока он не будет явно отключен.

Что можно проверить с помощью следующего кода:

public static void main(String[] args) {
    check(new JFrame(), "just creating a JFrame", x -> {});
    check(new JFrame(), "creating and connecting a JFrame", JFrame::pack);
    check(Frame.getFrames()[0], "calling dispose()", Frame::dispose);
}
private static <T> void check(T obj, String description, Consumer<T> action) {
    System.out.println(description);
    action.accept(obj);
    WeakReference<T> r = new WeakReference<>(obj);
    obj = null;
    System.gc();
    if(r.get() == null) System.out.println("collected immediately");
    else {
        System.runFinalization();
        System.gc();
        if(r.get() == null) System.out.println("collected after finalization");
        else System.out.println("still alive");
    }
}

, который будет печатать

just creating a JFrame
collected immediately
creating and connecting a JFrame
still alive
calling dispose()
collected after finalization

в типичных реализациях.

Стоит отметить, что кадр, который никогда не был подключен к устройству отображения, сразу собирается как обычный объект, тогда как кадр который был подключен и позднее отключен с помощью вызова dispose(), требуется действие очистки, которое происходит после первого запуска сборщика мусора.

Кроме того, в примере используется pack() вместо setVisible(true), чтобы продемонстрируйте, что кадр может быть подключен к устройству отображения, не будучи видимым. Это делает разницу между isDisplayable(), который отражает, подключен ли компонент к экранному устройству, и isVisible(), который сообщает, было ли установлено свойство visible до true. Наконец, компонент сообщает isShowing() как true, когда он отображается и отображается, а все его родители показывают.

...