Когда в Java вызывается метод finalize ()?


person Rajesh Kumar J    schedule 24.03.2010    source источник
comment
В качестве побочного примечания: finalize помечен как устаревший в Java 9   -  person Reg    schedule 27.10.2017
comment
взгляните: infoq.com/news/2017/03/Java- Завершить - устарело   -  person wleao    schedule 03.12.2017
comment
если что-то имеет ссылку на ваш объект или даже на класс. finalize() и сборка мусора не оказывает никакого влияния.   -  person ha9u63ar    schedule 11.01.2018
comment
Он устарел, начиная с Java9. docs.oracle.com/javase/ 9 / документы / api / java / lang /   -  person srk    schedule 25.06.2020


Ответы (17)


В общем, лучше не полагаться на finalize() при очистке и т. Д.

Согласно Javadoc (который стоило бы прочитать), это:

Вызывается сборщиком мусора для объекта, когда сборщик мусора определяет, что на этот объект больше нет ссылок.

Как указал Иоахим, этого может никогда не случиться в жизни программы, если объект всегда доступен.

Кроме того, сборщик мусора не может быть запущен в определенное время. В общем, то, что я пытаюсь сказать, finalize(), вероятно, не лучший метод для использования в целом, если нет чего-то конкретного, для чего он вам нужен.

person Community    schedule 24.03.2010
comment
Другими словами (просто для пояснения для будущих читателей) он никогда не вызывается в основном классе, поскольку, когда основной класс закрывается, сбор мусора не требуется. ОС все равно очищает все, что использовалось приложением. - person Mark Jeronimus; 07.05.2012
comment
не лучший метод для использования ... если нет чего-то особенного, для чего он вам нужен - это предложение относится ко всем 100%, поэтому бесполезно. Ответ Иоахима Зауэра намного лучше - person B T; 08.03.2013
comment
@ Zom-B ваш пример полезен для разъяснения, но, чтобы быть педантичным, предположительно, его можно было бы вызвать в основном классе, если основной класс создает не-демонический поток, а затем возвращается? - person Tom G; 16.02.2014
comment
@PhillSacre, какая хорошая альтернатива деструктору / финализации в Java? - person Vikas Verma; 13.06.2014
comment
также не гарантируется, что он будет работать в каком-либо конкретном потоке. несколько методов финализации могут выполняться в параллельных потоках. - person Claude Martin; 23.07.2014
comment
Завершение работы - хорошая идея при работе со списками / объектами OpenGL, не так ли? - person WorldSEnder; 13.08.2014
comment
@VikasVerma, например, PhantomReference. - person Alexander Ruliov; 19.03.2015
comment
Итак, в каких ситуациях finalize может быть полезен? - person nbro; 21.05.2015
comment
@MarkJeronimus - На самом деле это не имеет значения. Метод finalize() для основного класса вызывается при сборке мусора ›› экземпляр ‹< класса, а не при завершении работы основного метода. Кроме того, основной класс может быть собранным до завершения работы приложения; например в многопоточном приложении, где основной поток создает другие потоки, а затем возвращается. (На практике потребуется нестандартный загрузчик классов ....) - person Stephen C; 10.09.2016
comment
@BT говорит об этом лучше всех - последняя строчка бесполезна. Я бы предложил удалить его. - person Daniel Soutar; 09.07.2018

Метод finalize вызывается, когда объект собирается получить сборщик мусора. Это может произойти в любое время после того, как он получит право на сборку мусора.

Обратите внимание: вполне возможно, что объект никогда не получает сборщик мусора (и поэтому finalize никогда не вызывается). Это может произойти, когда объект никогда не становится подходящим для gc (потому что он доступен в течение всего времени существования JVM) или когда сборка мусора фактически не выполняется между моментом, когда объект становится подходящим, и временем, когда JVM перестает работать (это часто происходит с простым тестовые программы).

Есть способы указать JVM запустить finalize на объектах, которые еще не вызывались, но их использование тоже не очень хорошая идея (гарантии этого метода также не очень сильны).

Если вы полагаетесь на finalize для правильной работы вашего приложения, значит, вы делаете что-то не так. finalize следует только использовать для очистки ресурсов (обычно не связанных с Java). И это точно, потому что JVM не гарантирует, что finalize когда-либо будет вызван для любого объекта.

person Joachim Sauer    schedule 24.03.2010
comment
Я принял ваши цитаты абсолютно верно. В противном случае мне нужно увеличить время жизни JVM, пока мой объект не будет уничтожен. Есть ли способ сделать это ??? - person Rajesh Kumar J; 24.03.2010
comment
Сэр любезно посмотрите на мой еще один вопрос, я упомянул программу - person Rajesh Kumar J; 24.03.2010
comment
Который из? У вас их куча =) (Кроме того, я согласен. Не используйте финализаторы ... если вы полагаетесь на них, значит, ваш фундаментальный дизайн ошибочен. Это слабость или сильная сторона дизайна, в Java нет C ++ деструкторы). - person mikek; 24.03.2010
comment
@ Раджеш. Нет. Это не вопрос продолжительности жизни. Вы можете поместить свою программу в бесконечный цикл (на годы), и если сборщик мусора не нужен, он никогда не запустится. - person ChrisCantrell; 26.09.2013
comment
@JoachimSauer, что является хорошей альтернативой деструктору / финализации в Java? - person Vikas Verma; 13.06.2014
comment
@VikasVerma: идеальная замена - ничто: они вам не понадобятся. Единственный случай, когда это имеет смысл, - это если ваш класс управляет каким-либо внешним ресурсом (например, TCP / IP-соединением, файлом ... всем, что не может обработать Java GC). В этих случаях интерфейс Closable (и идея, лежащая в его основе), вероятно, именно то, что вам нужно: заставить .close() закрыть / отбросить ресурс и потребовать от пользователя вашего класса вызвать его в нужное время. Вы можете добавить метод finalize просто для сохранения, но это будет скорее инструмент отладки, чем фактическое исправление (потому что он недостаточно надежен). - person Joachim Sauer; 13.06.2014
comment
@JoachimSauer, не могли бы вы подробнее остановиться на третьем абзаце, есть способы указать JVM запустить finalize для объектов ...? - person Pacerier; 18.07.2014
comment
@Pacerier: Я намеренно не вдавался в подробности, так как это опасная область, и независимо от того, насколько вы думаете, что она вам нужна, скорее всего, вы можете и должны решить эту проблему. Тем не менее, посмотрите здесь. - person Joachim Sauer; 18.07.2014
comment
Есть ли какой-либо метод, который JVM обязательно вызовет перед остановкой, выключением или выходом? - person Dragonborn; 13.02.2015
comment
@Dragonborn: на самом деле это совсем другой вопрос, и его следует задавать отдельно. Существуют ловушки завершения работы, но они не гарантируются, если JVM неожиданно завершает работу (также известный как сбой). Но их гарантии значительно сильнее, чем у финализаторов (и они безопаснее). - person Joachim Sauer; 13.02.2015
comment
В вашем последнем абзаце говорится, что его следует использовать только для очистки ресурсов, даже если нет гарантии, что он когда-либо будет вызван. Говорит ли это об оптимизме? Я бы предположил, что что-то ненадежное, поскольку это тоже не подходит для очистки ресурсов. - person Jeroen Vannevel; 18.04.2015
comment
Финализаторы иногда могут спасти положение ... У меня был случай, когда сторонняя библиотека использовала FileInputStream, не закрывая его. Мой код вызывал код библиотеки, а затем пытался переместить файл, но безуспешно, потому что он все еще был открыт. Мне пришлось принудительно вызвать System.gc() для вызова FileInputStream :: finalize (), после чего я мог переместить файл. - person Elist; 08.08.2018

protected void finalize() throws Throwable {}
  • каждый класс наследует метод finalize() от java.lang.Object
  • метод вызывается сборщиком мусора, когда он определяет, что ссылки на объект больше не существуют
  • метод финализации объекта не выполняет никаких действий, но может быть отменен любым классом.
  • обычно его следует переопределить, чтобы очистить ресурсы, не относящиеся к Java, т.е. закрыть файл
  • при переопределении finalize() хорошей практикой программирования является использование оператора try-catch-finally и всегда вызывать super.finalize(). Это мера безопасности, чтобы вы случайно не пропустили закрытие ресурса, используемого объектами, вызывающими класс.

    protected void finalize() throws Throwable {
         try {
             close();        // close open files
         } finally {
             super.finalize();
         }
     }
    
  • любое исключение, выданное finalize() во время сборки мусора, останавливает финализацию, но в противном случае игнорируется

  • finalize() никогда не запускается более одного раза на любом объекте

цитата из: http://www.janeg.ca/scjp/gc/finalize.html < / а>

Вы также можете проверить эту статью:

person XpiritO    schedule 24.03.2010
comment
Статья JavaWorld, на которую вы ссылаетесь, относится к 1998 году и содержит несколько интересных советов, в частности предложение о том, чтобы вызвать System.runFinalizersOnExit (), чтобы гарантировать запуск финализаторов до выхода из JVM. Этот метод в настоящее время считается устаревшим, с комментарием «Этот метод по своей сути небезопасен. Это может привести к тому, что финализаторы будут вызваны для живых объектов, в то время как другие потоки одновременно манипулируют этими объектами, что приведет к неустойчивому поведению или тупиковой ситуации. Так что я не буду этого делать. - person Greg Chabala; 14.06.2011
comment
Поскольку runFinalizerOnExit () НЕ является потокобезопасным, можно сделать так: Runtime.getRuntime (). AddShutdownHook (new Thread () {public void run () {destroyMyEnclosingClass ();}}); в конструкторе класса. - person Ustaman Sangat; 25.07.2012
comment
@Ustaman Sangat Это способ сделать это, но помните, что это устанавливает ссылку на ваш экземпляр из shutdownHook, что в значительной степени гарантирует, что ваш класс никогда не будет собираться сборщиком мусора. Другими словами, это утечка памяти. - person pieroxy; 18.06.2013
comment
@pieroxy, хотя я согласен с тем, что все остальные здесь не используют finalize () ни для чего, я не понимаю, почему должна быть ссылка из ловушки выключения. Можно было иметь мягкую ссылку. - person Ustaman Sangat; 20.06.2013

Метод Java finalize() не является деструктором и не должен использоваться для обработки логики, от которой зависит ваше приложение. В спецификации Java говорится, что нет никакой гарантии, что метод finalize вообще будет вызван во время работы приложения.

Вероятно, вам нужна комбинация finally и метода очистки, например:

MyClass myObj;

try {
    myObj = new MyClass();

    // ...
} finally {
    if (null != myObj) {
        myObj.cleanup();
    }
}

Это правильно обработает ситуацию, когда конструктор MyClass() выдает исключение.

person rsp    schedule 24.03.2010
comment
@Anatoly неправильное редактирование, оно упускает ситуацию, когда конструктор MyClass() выдает исключение. Это вызовет NPE в новой версии примера. - person rsp; 27.11.2020

См. Эффективная Java, 2-е издание, стр. 27. Совет 7. Избегайте финализаторов

Финализаторы непредсказуемы, часто опасны и, как правило, не нужны. никогда не делайте в финализаторе ничего критичного по времени. никогда не полагайтесь на финализатор для обновления критического постоянного состояния.

Чтобы завершить ресурс, используйте вместо этого try-finally:

// try-finally block guarantees execution of termination method
Foo foo = new Foo(...);
try {
    // Do what must be done with foo
    ...
} finally {
    foo.terminate(); // Explicit termination method
}
person Hao Deng    schedule 01.07.2013
comment
или используйте try-with-resources - person Gabriel Garcia; 12.05.2017
comment
Это предполагает, что время жизни объекта находится в пределах одной функции. Что, конечно, не тот случай, о котором идет речь в OP, и это не тот случай, который в основном кому-то нужен. Подумайте о счетчике ссылок на возвращаемое значение механизма кэширования. Вы хотите освободить запись в кеше, когда будет освобождена последняя ссылка, но вы не знаете, когда будет освобождена последняя ссылка. finalize () может, например, уменьшать счетчик ссылок ... но если вы требуете, чтобы ваши пользователи явно вызывали бесплатную функцию, вы запрашиваете утечку памяти. обычно я просто делаю и то, и другое (функция выпуска + двойная проверка при завершении ...) ... - person Erik Aronesty; 26.10.2018

Когда в Java вызывается метод finalize()?

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

  • Если объект никогда не становится недоступным, finalize() никогда не будет вызван для него.

  • Если GC не запускается, то finalize() может никогда не быть вызван. (Обычно сборщик мусора запускается только в том случае, если JVM решает, что мусора достаточно, чтобы его использовать.)

  • Прежде чем сборщик мусора определит, что конкретный объект недоступен, может пройти несколько циклов сборки мусора. (Сборщики мусора Java обычно являются сборщиками "поколений" ...)

  • Как только сборщик мусора обнаруживает, что объект недоступен и может быть завершен, он помещается в очередь завершения. Завершение обычно происходит асинхронно с обычным сборщиком мусора.

(Спецификация JVM фактически позволяет JVM никогда запускать финализаторы ... при условии, что она не освобождает пространство, используемое объектами. JVM, которая была реализованный таким образом будет парализован / бесполезен, но если такое поведение «разрешено».)

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

Единственное законное использование финализации - очистка ресурсов, связанных с объектами, которые были потеряны кодом приложения. Даже в этом случае вы должны попытаться написать код приложения так, чтобы он вообще не терял объекты. (Например, используйте Java 7+ try-with-resources, чтобы гарантировать, что close() всегда вызывается ...)


Я создал тестовый класс, который записывает в файл при вызове метода finalize () путем его переопределения. Не выполняется. Кто-нибудь может сказать мне причину, по которой он не выполняется?

Сложно сказать, но есть несколько возможностей:

  • Объект не собирается сборщиком мусора, потому что он все еще доступен.
  • Объект не собирается сборщиком мусора, потому что сборщик мусора не запускается до завершения теста.
  • Объект находит сборщик мусора и помещает сборщик мусора в очередь финализации, но финализация не завершается до завершения вашего теста.
person Stephen C    schedule 24.03.2010

Поскольку существует неопределенность при вызове метода finalize () JVM (не уверен, будет ли выполнена переопределенная finalize () или нет), для целей исследования лучший способ наблюдать, что происходит при вызове finalize (), - это заставить JVM вызывать сборку мусора командой System.gc().

В частности, finalize () вызывается, когда объект больше не используется. Но когда мы пытаемся вызвать его, создавая новые объекты, уверенности в его вызове нет. Итак, для уверенности мы создаем null объект c, который, очевидно, не будет использоваться в будущем, поэтому мы видим финальный вызов объекта c.

Пример

class Car {

    int maxspeed;

    Car() {
        maxspeed = 70;
    }

    protected void finalize() {

    // Originally finalize method does nothing, but here we override finalize() saying it to print some stmt
    // Calling of finalize is uncertain. Difficult to observe so we force JVM to call it by System.gc(); GarbageCollection

        System.out.println("Called finalize method in class Car...");
    }
}

class Bike {

    int maxspeed;

    Bike() {
        maxspeed = 50;
    }

    protected void finalize() {
        System.out.println("Called finalize method in class Bike...");
    }
}

class Example {

    public static void main(String args[]) {
        Car c = new Car();
        c = null;    // if c weren`t null JVM wouldn't be certain it's cleared or not, null means has no future use or no longer in use hence clears it
        Bike b = new Bike();
        System.gc();    // should clear c, but not b
        for (b.maxspeed = 1; b.maxspeed <= 70; b.maxspeed++) {
            System.out.print("\t" + b.maxspeed);
            if (b.maxspeed > 50) {
                System.out.println("Over Speed. Pls slow down.");
            }
        }
    }
}

Вывод

    Called finalize method in class Car...
            1       2       3       4       5       6       7       8       9
    10      11      12      13      14      15      16      17      18      19
    20      21      22      23      24      25      26      27      28      29
    30      31      32      33      34      35      36      37      38      39
    40      41      42      43      44      45      46      47      48      49
    50      51Over Speed. Pls slow down.
            52Over Speed. Pls slow down.
            53Over Speed. Pls slow down.
            54Over Speed. Pls slow down.
            55Over Speed. Pls slow down.
            56Over Speed. Pls slow down.
            57Over Speed. Pls slow down.
            58Over Speed. Pls slow down. 
            59Over Speed. Pls slow down.
            60Over Speed. Pls slow down.
            61Over Speed. Pls slow down.
            62Over Speed. Pls slow down.
            63Over Speed. Pls slow down.
            64Over Speed. Pls slow down.
            65Over Speed. Pls slow down.
            66Over Speed. Pls slow down.
            67Over Speed. Pls slow down.
            68Over Speed. Pls slow down.
            69Over Speed. Pls slow down.
            70Over Speed. Pls slow down.

Примечание. Даже после печати до 70 и после того, как объект b не используется в программе, существует неопределенность, очищен ли b JVM или нет, поскольку «Вызывается метод finalize в классе Bike ...» не печатается.

person techloris_109    schedule 13.05.2015
comment
Вызов System.gc(); не гарантирует, что сборка мусора действительно будет запущена. - person Simon Forsberg; 21.09.2015
comment
Также не гарантируется, какой вид коллекции будет запущен. Актуально, поскольку большинство сборщиков мусора Java являются сборщиками поколений. - person Stephen C; 22.01.2017

finalize распечатает счетчик для создания класса.

protected void finalize() throws Throwable {
    System.out.println("Run F" );
    if ( checkedOut)
        System.out.println("Error: Checked out");
        System.out.println("Class Create Count: " + classCreate);
}

главный

while ( true) {
    Book novel=new Book(true);
    //System.out.println(novel.checkedOut);
    //Runtime.getRuntime().runFinalization();
    novel.checkIn();
    new Book(true);
    //System.runFinalization();
    System.gc();

Как вы видете. Следующий результат показывает, что gc был выполнен первый раз, когда количество классов равно 36.

C:\javaCode\firstClass>java TerminationCondition
Run F
Error: Checked out
Class Create Count: 36
Run F
Error: Checked out
Class Create Count: 48
Run F
person user1623624    schedule 24.11.2012

В последнее время столкнувшись с методами финализатора (чтобы избавиться от пулов соединений во время тестирования), я должен сказать, что финализатору не хватает многих вещей. Используя VisualVM для наблюдения, а также используя слабые ссылки для отслеживания фактического взаимодействия, я обнаружил, что в среде Java 8 (Oracle JDK, Ubuntu 15) верны следующие вещи:

  • Finalize не вызывается сразу, Finalizer (часть GC) неуловимо владеет ссылкой индивидуально
  • Сборщик мусора по умолчанию объединяет недостижимые объекты
  • Finalize вызывается массово, указывая на детали реализации, что существует определенная фаза, на которой сборщик мусора освобождает ресурсы.
  • Вызов System.gc () часто не приводит к более частой финализации объектов, он просто приводит к тому, что Finalizer быстрее узнает о недоступном объекте.
  • Создание дампа потока почти всегда приводит к запуску финализатора из-за высоких накладных расходов кучи во время выполнения дампа кучи или какого-либо другого внутреннего механизма.
  • Швы финализации должны быть связаны либо требованиями к памяти (высвободить больше памяти), либо списком объектов, помеченных для завершения, ростом определенного внутреннего лимита. Поэтому, если у вас есть много завершаемых объектов, фаза завершения будет запускаться чаще и раньше по сравнению с несколькими.
  • Были обстоятельства, что System.gc () запускал finalize напрямую, но только в том случае, если ссылка была локальной и недолговечной. Это может быть связано с поколением.

Последняя мысль

Метод Finalize ненадежен, но может использоваться только для одной цели. Вы можете гарантировать, что объект был закрыт или удален до того, как он был собран сборщиком мусора, что позволяет реализовать отказоустойчивость, если объекты с более сложным жизненным циклом, включающим действие по окончании срока службы, обрабатываются правильно. Это единственная причина, по которой я могу придумать, что стоит переопределить ее.

person Martin Kersten    schedule 25.09.2015

Объект получает право на сборку мусора или сборщик мусора, если он недоступен из каких-либо живых потоков или каких-либо статических ссылок, другими словами, вы можете сказать, что объект становится подходящим для сборки мусора, если все его ссылки равны нулю. Циклические зависимости не считаются ссылочными, поэтому, если объект A имеет ссылку на объект B, а объект B имеет ссылку на объект A и у них нет другой живой ссылки, тогда оба объекта A и B будут иметь право на сборку мусора. Обычно объект имеет право на сборку мусора в Java в следующих случаях:

  1. Все ссылки на этот объект явно имеют значение null, например. объект = ноль
  2. Объект создается внутри блока, и ссылка выходит за пределы области действия после выхода управления из этого блока.
  3. Для родительского объекта установлено значение null, если объект содержит ссылку на другой объект и когда вы устанавливаете нулевую ссылку на объект-контейнер, дочерний или содержащийся объект автоматически получает право на сборку мусора.
  4. Если объект имеет только живые ссылки через WeakHashMap, он будет иметь право на сборку мусора.
person Tushar Trivedi    schedule 09.04.2013
comment
Если поле final объекта используется повторно во время медленных вычислений, и объект никогда не будет использоваться после этого, будет ли объект оставаться активным до последнего запроса исходного кода поля, или JIT может скопировать поле в временная переменная, а затем отказаться от объекта перед вычислением? - person supercat; 27.04.2017
comment
@supercat: оптимизатор может переписать код в форму, в которой объект изначально не создается; в этом случае он может быть завершен сразу после завершения его конструктора, если только синхронизация не устанавливает порядок между использованием объекта и финализатором. - person Holger; 04.05.2017
comment
@Holger: В тех случаях, когда JIT может видеть все, что когда-либо произойдет с объектом между его созданием и закрытием, я не вижу причин для JIT запускать финализатор раньше. Реальный вопрос будет заключаться в том, что должен делать код, чтобы гарантировать, что финализатор не сможет сработать в рамках определенного метода. В .NET есть функция GC.KeepAlive(), которая ничего не делает, кроме как заставляет сборщик мусора предполагать, что он может использовать объект, но я не знаю такой функции в Java. Для этой цели можно использовать volatile переменную, но использование переменной исключительно для этой цели было бы расточительным. - person supercat; 04.05.2017
comment
@supercat: JIT не запускает финализацию, он просто упорядочивает код, чтобы не сохранять ссылку, хотя может быть полезно напрямую поставить FinalizerReference в очередь, чтобы не потребовался цикл GC, чтобы узнать, что есть нет ссылок. Синхронизации достаточно, чтобы гарантировать связь происходит до; поскольку финализация может (фактически выполняется) выполняться в другом потоке, это часто формально необходимо в любом случае. Java 9 собирается добавить _ 2_ - person Holger; 04.05.2017
comment
@Holger: Если JIT оптимизирует создание объекта, единственный Finalize будет вызван вообще, если JIT произвел код, который сделал бы это напрямую. Ожидается ли обычно код синхронизации для объектов, которые предполагается использовать только в одном потоке? Если объект выполняет какое-то действие, которое необходимо отменить, прежде чем он будет оставлен (например, открытие соединения с сокетом и получение исключительного права на использование ресурса на другом конце), то, что финализатор закроет соединение, пока код все еще использует сокет, будет катастрофой. . Было бы нормально, если бы код использовал синхронизацию ... - person supercat; 04.05.2017
comment
... исключительно с целью предотвращения преждевременного закрытия соединения финализатором? - person supercat; 04.05.2017
comment
@supercat: поскольку финализаторы запускаются в произвольном потоке, использование потоковобезопасной конструкции обязательно при использовании finalize(). Но когда вы полагаетесь исключительно на неизменяемость для достижения этой потоковой безопасности, отсутствие явного использования объекта действительно может иметь катастрофические последствия. Это реальная проблема. Вот почему предпочтительнее использовать эталонный API; там у вас есть полный контроль над тем, когда и в каком потоке вы опрашиваете ReferenceQueue для очистки ресурсов. - person Holger; 05.05.2017

Метод finalize не гарантируется. Этот метод вызывается, когда объект становится подходящим для сборки мусора. Есть много ситуаций, когда объекты не могут быть обработаны сборщиком мусора.

person giri    schedule 24.03.2010
comment
Неправильно. Вы говорите, что объект завершается, когда становится недоступным. Фактически он вызывается при фактическом сборе метода. - person Stephen C; 22.01.2017

Иногда при разрушении объект должен совершить действие. Например, если у объекта есть не-java-ресурс, такой как дескриптор файла или шрифт, вы можете убедиться, что эти ресурсы освобождены, прежде чем уничтожать объект. Для управления такими ситуациями java предлагает механизм, называемый «финализация». Завершив его, вы можете определить конкретные действия, которые происходят, когда объект собирается удалить из сборщика мусора. Чтобы добавить финализатор в класс, просто определите метод finalize (). Время выполнения Java вызывает этот метод всякий раз, когда он собирается удалить объект этого класса. В методе finalize method () вы указываете действия, которые необходимо выполнить перед уничтожением объекта. Сборщик мусора периодически ищет объекты, которые больше не ссылаются на какое-либо рабочее состояние или косвенно на любой другой объект со ссылкой. Перед выпуском ресурса среда выполнения Java вызывает метод finalize () для объекта. Метод finalize () имеет следующую общую форму:

protected void finalize(){
    // This is where the finalization code is entered
}

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

person Amarildo    schedule 02.07.2017

Класс, в котором мы переопределяем метод finalize

public class TestClass {    
    public TestClass() {
        System.out.println("constructor");
    }

    public void display() {
        System.out.println("display");
    }
    @Override
    public void finalize() {
        System.out.println("destructor");
    }
}

Вероятность вызова метода finalize

public class TestGarbageCollection {
    public static void main(String[] args) {
        while (true) {
            TestClass s = new TestClass();
            s.display();
            System.gc();
        }
    }
}

когда память перегружена объектами дампа, gc вызовет метод finalize

запустите и посмотрите консоль, где вы не найдете часто вызываемого метода finalize; когда память перегружается, будет вызван метод finalize.

person pradeep    schedule 01.02.2016

Java позволяет объектам реализовывать метод finalize (), который может быть вызван.

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

Если сборщик мусора не запускается, метод не вызывается.

Если сборщику мусора не удается собрать объект и он пытается запустить его снова, метод не вызывается во второй раз.

На практике вы вряд ли будете использовать его в реальных проектах.

Просто имейте в виду, что он может не быть вызван и определенно не будет вызываться дважды. Метод finalize () может запускаться ноль или один раз.

В следующем коде метод finalize () не производит никаких выходных данных, когда мы запускаем его, поскольку программа завершается до того, как возникнет необходимость в запуске сборщика мусора.

Источник

person JavaDev    schedule 25.07.2016

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

Пример:

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

person AyukNayr    schedule 17.04.2018

Как указано в https://wiki.sei.cmu.edu/confluence/display/java/MET12-J.+Do+not+use+finalizers,

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

person Utkarsh    schedule 30.11.2019

Попробуйте запустить эту программу для лучшего понимания

public class FinalizeTest 
{       
    static {
        System.out.println(Runtime.getRuntime().freeMemory());
    }

    public void run() {
        System.out.println("run");
        System.out.println(Runtime.getRuntime().freeMemory());
    }

     protected void finalize() throws Throwable { 
         System.out.println("finalize");
         while(true)
             break;          
     }

     public static void main(String[] args) {
            for (int i = 0 ; i < 500000 ; i++ ) {
                    new FinalizeTest().run();
            }
     }
}
person user3836455    schedule 17.01.2017