Какова цель завершения в Java?

Мое понимание завершения - это:

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

Сборщик "мусора" затем разыменовывает объект. Иногда, нет никакого пути к сборщику "мусора" для доступа к объекту. Затем завершите, вызывается, чтобы сделать заключительную уборку, обрабатывающую, после которого может быть вызван сборщик "мусора".

Действительно ли это - детальное описание завершения?

11
задан 4 revs, 2 users 76%user244333 13 October 2017 в 19:56
поделиться

5 ответов

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

Завершение было предназначено для очистки ресурсов, полученных объектом (не памяти, а других ресурсов, например, дескрипторов файлов, портов, соединений с БД и т. Д.). Однако на самом деле это не сработало: - (

  • непредсказуемо, когда finalize () будет вызван
  • на самом деле, нет никакой гарантии, что finalize () будет вызываться когда-либо!

Таким образом, даже если бы он гарантированно был вызван, это не было бы хорошим местом для высвобождения ресурсов: к тому времени, когда он будет вызван для освобождения всех соединений с БД, которые вы открыли, в системе может быть полностью закончатся свободные подключения, и ваше приложение больше не будет работать.

15
ответ дан 3 December 2019 в 02:01
поделиться

Из этой статьи :

Любые экземпляры классов, которые реализуют метод finalize (), являются {{ 1}} часто называют финализируемыми объектами. Они не будут немедленно удалены сборщиком мусора Java, когда на них больше не ссылаются. Вместо этого сборщик мусора Java добавляет объекты в специальную очередь для процесса финализации . Обычно это выполняется специальным потоком, который называется "Обработчик ссылок" на некоторых виртуальных машинах Java . Во время этого процесса финализации поток «Finalizer» будет выполнять каждый метод finalize () объектов. Только после успешного завершения метода finalize () объект будет передан для сборки мусора Java , чтобы освободить его пространство по «будущей» сборке мусора.

Вы можете делать практически все, что угодно в методе finalize () вашего класса . При этом не ожидайте, что пространство памяти, занимаемое каждым объектом, будет освобождено сборщиком мусора Java, когда объект больше не упоминается или больше не требуется . Почему? Не гарантируется, что метод finalize () завершит выполнение своевременно . В худшем случае он может даже не быть вызван , даже если больше нет ссылок на объект. Это означает, что не гарантируется, что какие-либо объекты , у которых есть метод finalize (), будут собраны мусором.

Кроме того, в этой статье от Sun есть несколько хороших диаграмм, объясняющих этот процесс.

7
ответ дан 3 December 2019 в 02:01
поделиться

Нет. Метод finalize () запускается только в том случае, если сборщик мусора пытается вернуть ваш объект.

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

6
ответ дан 3 December 2019 в 02:01
поделиться

Собственно, вот поведение метода finalize ():

После запуска сборщика мусора (виртуальная машина решает, что ей необходимо освободить память, вы не может заставить его запускаться) и решил собрать память из этого объекта (что означает, что на него больше НЕТ ссылок, по крайней мере, из доступных объектов), непосредственно перед тем, как он удалит занятую им память, он запускает метод finalize ( ) на объекте. Вы можете быть уверены, что если мусор будет собран, объект будет запускать finalize () непосредственно перед тем, как он исчезнет, ​​но вы не можете быть уверены, что он вообще получит GC, поэтому вам не следует полагаться на этот метод для выполнения какой-либо дезинфекции. . Вы должны запускать операторы очистки внутри блоков finally {} и не использовать finalize (), поскольку его выполнение не гарантируется.

Кроме того, некоторые люди провели тесты производительности и показали, что метод finalize несколько замедляет создание / уничтожение объекта. Я не могу вспомнить источник, поэтому относитесь к этой информации как к не очень надежной. :)

5
ответ дан 3 December 2019 в 02:01
поделиться

Финализация используется для очистки ресурсов, которые не могут быть освобождены сборщиком мусора. Например, рассмотрим программу, которая выделяет (через какой-нибудь native API) ресурсы непосредственно из ОС. Обычно это дает некий "хэндл" (дескриптор файла UNIX или Windows HANDLE, или что-то подобное):

class Wrapper {
    private long handle;

    private Handle(long h) {
        handle = h;
    }

    private static native long getHandleFromOS();

    static Wrapper allocate() {
        return new Handle(getHandleFromOS());
    }
}

Итак, что произойдет, если ваш код выделит экземпляр класса Wrapper? Ну, класс выделяет какой-то специфический для ОС ресурс и хранит ссылку на него (handle) в переменной-члене. Но что произойдет, если последняя Java-ссылка на экземпляр обертки будет потеряна? Теперь сборщик мусора (в какой-то момент) вернет пространство исчезнувшего экземпляра обертки. Но что произойдет с ресурсом ОС, выделенным оберткой? В описанном выше сценарии он будет утечен, что плохо, если это дорогостоящий ресурс, такой как дескриптор файла.

Для того чтобы ваш код мог очиститься в таком сценарии, существует метод finalize.

class Wrapper {
    private long handle;

    private Handle(long h) {
        handle = h;
    }

    protected void finalize() {
        returnHandleToOS(handle);
    }

    private static native long getHandleFromOS();
    private static native void returnHandleToOS(long handle);

    static Wrapper allocate() {
        return new Handle(getHandleFromOS());
    }
}

Теперь, когда GC возвращает пространство экземпляра обертки, финализатор следит за тем, чтобы ресурс был правильно возвращен в ОС.

Все это звучит красиво, но, как уже отмечали другие, недостатком является то, что финализация по своей природе ненадежна: вы не знаете, когда будет запущен финализатор. Хуже того: нет никаких гарантий, что он вообще будет запущен. Поэтому лучше всего предоставить механизм dispose и использовать финализацию только в качестве страховочной сети на случай, если клиенты вашего класса забудут правильно утилизировать свои ссылки:

class Wrapper {
    private long handle;

    private Handle(long h) {
        handle = h;
    }

    protected void finalize() {
        if( handle != 0 ) returnHandleToOS(handle);
    }

    public void dispose() {
        returnHandleToOS(handle);
        handle = 0;
    }

    private static native long getHandleFromOS();
    private static native void returnHandleToOS(long handle);

    static Wrapper allocate() {
        return new Handle(getHandleFromOS());
    }
}
2
ответ дан 3 December 2019 в 02:01
поделиться
Другие вопросы по тегам:

Похожие вопросы: