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

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

16 ответов


вообще лучше не полагаться на finalize() сделать любую уборку и т. д.

по словам Javadoc (которые стоило бы прочитать), это:

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

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


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

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

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

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


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

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

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

ЦИТ. по: http://www.janeg.ca/scjp/gc/finalize.html

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


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

то, что вы, вероятно, хотите, является комбинацией finally и метод очистки, как в:

MyClass myObj;

try {
    myObj = new MyClass();

    // ...
} finally {

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

Проверьте эффективную 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
}

когда finalize() метод в Java?

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

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

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

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

  • как только GC обнаруживает объект недостижимым и завершаемым, он помещается в очередь завершения. Завершение обычно происходит асинхронно с нормальным СБОРЩИК МУСОРА.

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

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

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


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

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

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

поскольку существует неопределенность в вызове метода 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..."не печатается.


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);
}

main

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

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

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

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

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


завершить метода не гарантируется.Этот метод вызывается, когда объект становится готовой для GC. Существует много ситуаций, когда объекты не могут быть собраны мусора.


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

  1. все ссылки на этот объект явно установлены в null, например object = null
  2. объект создается внутри блока, и ссылка выходит из области после выхода элемента управления из этого блока.
  3. родительский объект имеет значение null, если объект содержит ссылку на другой объект и когда вы устанавливаете ссылку на объект контейнера null, дочерний или содержащий объект автоматически получает право на мусор коллекция.
  4. если объект имеет только живые ссылки через WeakHashMap, он будет иметь право на сборку мусора.

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

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

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


класс, где мы переопределяем метод 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.


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

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

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

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

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

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

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

источник


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

пример:

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


попробовать runiing эту программу для лучшего понимания

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();
            }
     }
}