Коли в Java викликується метод finalize ()?


330

Мені потрібно знати, коли finalize()метод викликається в JVM. Я створив тестовий клас, який записує у файл, коли finalize()метод викликається шляхом його заміни. Він не виконується. Хтось може сказати мені причину, чому вона не виконується?


34
Так само , як примітка боку: фіналізації позначений як застарілий в Java 9
Реєстр


якщо щось має посилання на ваш об’єкт або навіть клас. finalize()а вивезення сміття не впливає.
ha9u63ar

Відповіді:


273

Взагалі краще не покладатися на finalize()будь-яке прибирання тощо.

За словами Javadoc (який варто було б прочитати), це:

Викликається сміттєзбірником на об'єкт, коли збирання сміття визначає, що більше немає посилань на об'єкт.

Як зазначав Йоахім, це може ніколи не траплятися в житті програми, якщо об'єкт завжди доступний.

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


19
Іншими словами (просто для уточнення для майбутніх читачів) його ніколи не називають основним класом, оскільки, коли основний клас закривається, сміття не потрібно збирати. ОС очищає все, що додаток все одно використовував.
Марк Єронімус

113
"не найкращий метод для використання ... якщо у вас є щось конкретне, вам це потрібно" - е, це речення застосовується до 100% усього, тому не є корисним. Відповідь Йоахіма Зауера набагато краща
BT

1
@ Zom-B ваш приклад корисний для уточнення, але просто для педантичності, імовірно, його можна було б викликати в основному класі, якщо основний клас створить недемонну нитку і потім повернеться?
Том Г

3
То в яких ситуаціях finalizeбуло б корисно?
nbro

3
@MarkJeronimus - Насправді це не має значення. finalize()Метод на для основного класу викликається , коли >> << екземпляр класу є збір сміття, не тоді , коли основний метод завершується. Крім того, основним класом може бути сміття, зібране до закінчення роботи програми; наприклад, у багатопотоковому додатку, де "головний" потік створює інші потоки, а потім повертається. (На практиці потрібен буде нестандартний завантажувач класів ....)
Stephen C

379

finalizeМетод викликається , коли об'єкт збирається отримати сміття. Це може бути в будь-який час після того, як він стане прийнятним до вивезення сміття.

Зауважте, що цілком можливо, що об’єкт ніколи не збирає сміття (і, отже, finalizeйого ніколи не називають). Це може статися, коли об’єкт ніколи не може отримати право на gc (тому що він доступний протягом усього терміну експлуатації JVM) або коли збирання сміття насправді не проходить між часом, коли об’єкт стане прийнятним і тим часом, коли JVM перестане працювати (це часто відбувається з простим тестові програми).

Існують способи сказати JVM працювати finalizeна об'єктах, до яких ще не зверталися, але їх використання також не є хорошою ідеєю (гарантії цього методу теж не дуже сильні).

Якщо ви покладаєтесь на finalizeправильну роботу вашої програми, то ви робите щось не так. finalizeслід використовувати лише для очищення (як правило, не Java) ресурсів. І це саме тому, що JVM не гарантує, що finalizeколи-небудь викликається будь-який об'єкт.


2
@Rajesh. Ні. Це не "тривалість життя". Ви можете помістити свою програму в нескінченний цикл (роками), і якщо сміттєзбірник не потрібен, він ніколи не працюватиме.
ChrisCantrell

5
@VikasVerma: ідеальною заміною є нічого: вони вам не потрібні. Єдиний випадок, коли це мало б сенс, якщо ваш клас керує деяким зовнішнім ресурсом (наприклад, з'єднання TCP / IP, файл ... все, з чим не може працювати Java GC). У цих випадках Closableінтерфейс (і ідея, що стоїть за ним) є, мабуть, тим, що ви хочете: .close()закрийте / відкиньте ресурс і вимагайте від користувача вашого класу зателефонувати йому в потрібний час. Ви , можливо , хочете додати finalizeметод «просто бути зберегти», але це буде швидше інструмент налагодження , ніж фактичне виправлення (бо це не досить надійним).
Йоахім Зауер

4
@Dragonborn: це насправді зовсім інше питання, і його слід задавати окремо. Існують гачки відключення, але вони не гарантуються, якщо JVM несподівано вимкнеться (він же виходить з ладу). Але їх гарантії значно сильніші, ніж гарантії для фіналізаторів (і вони також безпечніші).
Йоахім Зауер

4
Ваш останній абзац говорить про те, що використовувати його потрібно лише для очищення ресурсів, хоча немає гарантії, що він коли-небудь буде закликаний. Це оптимізм говорить? Я б припустив, що щось ненадійне, оскільки це також не підходить для очищення ресурсів.
Єроен Ванневель

2
Фіналізатори іноді можуть врятувати день ... У мене був випадок, коли стороння бібліотека використовувала FileInputStream, ніколи не закриваючи її. Мій код зателефонував до коду бібліотеки, а потім спробував перемістити файл, але не вдалося, оскільки він все ще був відкритим. Мені довелося змусити виклик System.gc()викликати FileInputStream :: finalize (), тоді я міг перемістити файл.
Еліст

73
protected void finalize() throws Throwable {}
  • кожен клас успадковує finalize()метод від java.lang.Object
  • метод викликається сміттєзбірником, коли він визначає, що більше ніяких посилань на об'єкт не існує
  • метод завершення об'єкта не виконує жодних дій, але його може бути замінено будь-яким класом
  • як правило, це має бути скасовано для очищення не-Java-ресурсів, тобто закриття файлу
  • якщо переосмислення, finalize()це хороша практика програмування, щоб використовувати оператор try-catch-нарешті і завжди телефонувати 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

Ви також можете перевірити цю статтю:


25
Стаття JavaWorld, на яку ви посилаєтесь, складається з 1998 року і містить кілька цікавих порад, зокрема пропозицію про те, щоб зателефонувати System.runFinalizersOnExit (), щоб забезпечити запуск фіналізаторів до виходу JVM. Цей метод на даний момент застарілий, з коментарем "Цей метод по суті небезпечний. Це може призвести до виклику фіналізаторів на живі об'єкти, тоді як інші потоки одночасно маніпулюють цими об'єктами, що призводить до нерівномірної поведінки або тупику ". Тому я цього робити не буду.
Грег Чабала

3
Оскільки runFinalizerOnExit () НЕ безпечний для потоків, те, що можна зробити, це Runtime.getRuntime (). AddShutdownHook (новий Thread () {public void run () {killMyEnclosingClass ();}}); у конструкторі Класу.
Устаман Сангат

2
@Ustaman Sangat Це спосіб зробити це, але пам’ятайте, що це встановлює посилання на ваш примірник від shutdownHook, що в значній мірі гарантує, що ваш клас ніколи не збирає сміття. Іншими словами, це витік пам'яті.
п’єрокси

1
@pieroxy, хоча я погоджуюсь, що всі інші тут стосуються того, щоб не використовувати finalize () ні для чого, я не розумію, чому має бути посилання з гачка закриття. Можна сказати про слабку орієнтир.
Устаман Сангат

25

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

Тебе, можливо, хочеться - це комбінація finallyта спосіб очищення, як у:

MyClass myObj;

try {
    myObj = new MyClass();

    // ...
} finally {

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

20

Перевірте Ефективну Java, сторінка 2-го видання 27. Пункт 7: Уникайте фіналізаторів

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

Щоб припинити ресурс, використовуйте спробу-остаточно замість цього:

// 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
}

3
або скористайтеся пробними ресурсами
Габріель Гарсія

3
Це передбачає, що термін експлуатації об'єкта знаходиться в межах однієї функції. Звичайно, це не той випадок, на який посилається ОП, і це, в основному, не потрібно комусь. Подумайте "кількість опорних значень зворотного значення двигуна кешу". Ви хочете звільнити запис кешу, коли звільнений останній посилання, але ви не знаєте, коли буде звільнений останній. finalize () може зменшити кількість посилань, наприклад ..., але якщо ви вимагаєте від користувачів явно викликати безкоштовну функцію, ви вимагаєте витоку пам'яті. Зазвичай я просто виконую і те й інше (функція випуску + подвійна перевірка у
фіналі

16

Коли finalize()метод називається в Java?

Метод завершення буде викликаний після того, як GC виявить, що об'єкт більше недоступний, і до того, як він фактично поверне пам'ять, яку використовує об'єкт.

  • Якщо об’єкт ніколи не стає недосяжним, finalize()його ніколи не зазиватимуть.

  • Якщо GC не працює, то finalize()його ніколи не можна викликати. (Зазвичай, GC працює лише тоді, коли JVM вирішить, що, ймовірно, буде достатньо сміття, щоб зробити його вартим.)

  • Може знадобитися більше одного циклу GC, перш ніж GC визначить, що конкретний об'єкт недоступний. (Java GC - це типово "покоління" колекціонерів ...)

  • Після того як GC виявляє об'єкт недоступним і доопрацьованим, він розміщується у черзі на завершення. Фіналізація, як правило, відбувається асинхронно з нормальним GC.

(Специфікація JVM фактично дозволяє JVM ніколи не запускати фіналізатори ... за умови, що він не повертає простір, який використовують об'єкти. JVM, який був реалізований таким чином, буде каліком / марним, але це поведінка "дозволено" .)

Підсумок полягає в тому, що нерозумно покладатися на доопрацювання, щоб робити речі, які потрібно зробити в певні часові рамки. Це "найкраща практика" взагалі їх не використовувати. Повинен бути кращий (тобто більш надійний) спосіб робити все, що ви намагаєтеся зробити в finalize()методі.

Єдиним законним використанням для доопрацювання є очищення ресурсів, пов’язаних з об'єктами, які були втрачені кодом програми. Вже тоді вам слід спробувати написати код програми, щоб він не втрачав об'єкти в першу чергу. (Наприклад, використовуйте тест -ресурси Java 7+ для забезпечення того, що close()завжди викликається ...)


Я створив тестовий клас, який записує у файл, коли викликається метод finalize () шляхом його заміни. Він не виконується. Хтось може сказати мені причину, чому вона не виконується?

Важко сказати, але є кілька можливостей:

  • Об'єкт не збирається сміттям, оскільки він все ще доступний.
  • Об'єкт не збирається сміттям, оскільки GC не працює до завершення тесту.
  • Об'єкт знайдений GC та розміщений у черзі для завершення GC, але остаточне завершення не завершено до завершення тесту.

10

Оскільки існує невизначеність виклику методу finalize () методом JVM (не впевнений, виконуватиметься чи ні завершення, яке буде замінено), для цілей дослідження кращим способом спостерігати за тим, що відбувається при виклику 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, оскільки "Викликаний метод завершення в класі Bike ..." не друкується.


10
Телефонування System.gc();не є гарантією того, що збирання сміття буде фактично проведено.
Саймон Форсберг

3
Також не гарантується , що тип колекції буде працювати. Актуально, оскільки більшість GC Java є колекціонерами "покоління".
Стівен С

5

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

4

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

  • Фіналізація не називається негайно. Фіналізатор (частина GC) окремо володіє посиланням невловимо
  • Збірник сміття за замовчуванням об'єднує недоступні об'єкти
  • Фіналізація називається масово, вказуючи на деталі реалізації, що існує певна фаза, коли збирач сміття звільняє ресурси.
  • Виклик System.gc () часто не призводить до того, що об'єкти частіше допрацьовуються, це лише призводить до того, що Фіналізатор швидше усвідомлює недоступний об'єкт
  • Створення дамп-потоку майже завжди призводить до запуску фіналізатора через великі нагромадження під час виконання скиду купи чи іншого внутрішнього механізму
  • Шви доопрацювання повинні бути пов'язані або потребами пам’яті (звільнити більше пам’яті), або списком об’єктів, позначених для завершення вирощування певного внутрішнього обмеження. Отже, якщо у вас багато об'єктів, які завершуються, етап завершення буде запускатися частіше і раніше, порівняно з лише кількома
  • Були обставини, що System.gc () ініціював остаточне завершення, але лише якщо посилання було місцевим та недовгим. Це може бути пов'язано з поколінням.

Підсумкова думка

Метод доопрацювання недостовірний, але його можна використовувати лише для одного. Ви можете переконатися, що об’єкт був закритий або знешкоджений до того, як він був зібраний сміттям, що дозволяє здійснити безпечний збій, якщо з об'єктами, що мають складніші життєві циліндри, що включають дії, що закінчуються, правильно поводитись. Це єдина причина, про яку я можу вважати, що це варто для того, щоб перекрити це.


2

Об'єкт стає придатним для збору сміття або GC, якщо його не можна дістати з будь-яких прямих потоків або будь-яких статичних відхилень іншими словами, ви можете сказати, що об’єкт стає придатним для збору сміття, якщо всі його посилання є недійсними. Циклічні залежності не зараховуються як еталонні, тому якщо об’єкт A має посилання на об’єкт B, а об'єкт B має посилання на об'єкт A, і вони не мають жодної іншої реальної посилання, то обидва об'єкти A і B будуть придатні до збору сміття. Як правило, об’єкт стає придатним для збору сміття на Java у таких випадках:

  1. Всі посилання на цей об'єкт явно встановлені на null, наприклад object = null
  2. Об'єкт створюється всередині блоку, а посилання виходить з області дії, коли керує виходом із нього.
  3. Батьківський об'єкт встановлений на нуль, якщо об'єкт містить посилання на інший об'єкт і коли ви встановлюєте посилання на об'єкт контейнера нульовим, дочірній або міститься об'єкт автоматично стає придатним для збору сміття.
  4. Якщо на об'єкт є лише активні посилання через WeakHashMap, він буде придатний для збору сміття.

Якщо finalполе об'єкта використовується неодноразово під час повільних обчислень, і об'єкт ніколи не буде використовуватися після цього, чи буде об'єкт залишатися живим до останнього запиту вихідного коду, або чи може JIT скопіювати поле в тимчасова змінна, а потім відмовитися від об'єкта перед обчисленням?
supercat

@supercat: оптимізатор може переписати код у форму, де об'єкт створений не в першу чергу; у такому випадку він може бути завершений відразу після закінчення конструктора, якщо синхронізація не примушує замовлення між об'єктом використання та фіналізатором.
Холгер

@Holger: У випадках, коли JIT може побачити все, що коли-небудь трапиться з об'єктом між його створенням і залишенням, я не бачу причин, щоб JIT достроково звільнив фіналізатор. Справжнім питанням буде те, який код потрібно зробити для того, щоб фіналізатор не міг запускати певний метод. У .NET є GC.KeepAlive()функція, яка нічого не робить, окрім як змушує GC припускати, що він може використовувати об’єкт, але я не знаю такої функції в Java. Можна використовувати volatileзмінну для цієї мети, але використання змінної виключно для такої мети здасться марною.
supercat

@supercat: JIT не спрацьовує завершення, він просто впорядковує код, щоб не зберігати посилання, хоча, можливо, буде корисно безпосередньо переписувати FinalizerReference, так що йому не потрібен цикл GC, щоб з'ясувати, що немає посилання. Синхронізації достатньо, щоб забезпечити взаємини, що трапляються раніше ; оскільки фіналізація може (насправді є) працювати в іншій нитці, вона в будь-якому випадку формально необхідна. Java 9 додасть Reference.reachabilityFence
Holger

@Holger: Якщо JIT оптимізує створення об'єктів, єдиним викликом Finalizeвзагалі було б, якщо JIT створив код, який це зробив безпосередньо. Чи очікується, як правило, код синхронізації для об'єктів, які розраховують використовувати лише в одному потоці? Якщо об’єкт виконує якусь дію, яку потрібно скасувати перед тим, як її відмовити (наприклад, відкриття з'єднання сокету та отримання ексклюзивного використання ресурсу на іншому кінці), встановлення фіналізатора закрити з'єднання, поки код все ще використовує сокет, було б катастрофою . Було б нормально для коду використовувати синхронізацію ...
supercat

2

метод остаточного завершення не гарантується. Цей метод називається, коли об'єкт стає придатним до GC. Є багато ситуацій, коли об’єкти можуть не збирати сміття.


3
Неправильно. Що ви говорите, це те, що об’єкт допрацьовується, коли він стає недосяжним. Це насправді називається, коли метод фактично зібраний.
Стівен С

2

Іноді, коли він знищений, об’єкт повинен зробити дію. Наприклад, якщо об’єкт має не-Java-ресурс, такий як ручка файлу або шрифт, ви можете перевірити, що ці ресурси звільнені перед знищенням об'єкта. Для управління подібними ситуаціями java пропонує механізм, який називається "завершення". Завершивши його, ви можете визначити конкретні дії, які відбуваються, коли об’єкт збирається видалити зі сміттєзбірника. Щоб додати фіналізатор до класу, просто визначте метод finalize () . Час виконання Java викликає цей метод, коли збирається видалити об'єкт цього класу. У рамках методу завершення ()ви вказуєте дії, які слід виконати перед знищенням об'єкта. Колектор сміття періодично шукає об'єкти, які більше не посилаються на будь-який запущений стан або опосередковано на будь-який інший об'єкт з посиланням. Перед тим як вивільняти актив, час виконання Java викликає метод finalize () на об'єкті. Метод finalize () має таку загальну форму:

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

За допомогою захищеного ключового слова перешкоджає доступ до завершення () за кодом поза його класом. Важливо розуміти, що finalize () викликається безпосередньо перед вивезенням сміття. Наприклад, він не викликається, коли об'єкт залишає область. Це означає, що ви не можете знати, коли або якщо буде виконано завершення () . В результаті програма повинна надати інші засоби для звільнення системних ресурсів або інших ресурсів, які використовує об'єкт. Ви не повинні покладатися на finalize () для нормального запуску програми.


1

Клас, де ми перекриваємо метод доопрацювання

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

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

Шанси виправити метод доопрацювання

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

коли пам'ять перевантажена дамп-об'єктами, gc викличе метод завершення

запустіть і перегляньте консоль, де ви не знаходите метод завершення, який часто викликається, коли пам'ять перевантажується, тоді буде виклик метод завершення.


0

Java дозволяє об'єктам реалізувати метод, який називається finalize (), який може отримати виклик.

Метод finalize () викликається, якщо збирач сміття намагається зібрати об'єкт.

Якщо сміттєзбірник не працює, метод не викликається.

Якщо сміттєзбірник не зможе зібрати об'єкт і спробує запустити його знову, метод не викликається вдруге.

На практиці ви навряд чи зможете використовувати його в реальних проектах.

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

У наступному коді метод finalize () не видає результатів, коли ми запускаємо його, оскільки програма закінчується, перш ніж виникне потреба у запуску сміттєзбірника.

Джерело


0

finalize()називається безпосередньо перед вивезенням сміття. Він не називається, коли об’єкт виходить із сфери застосування. Це означає, що ви не можете знати, коли і навіть якщоfinalize() буде виконано.

Приклад:

Якщо ваша програма закінчиться до того, як відбудеться збирання сміття, вона finalize()не виконається. Тому його слід використовувати як резервну процедуру для забезпечення належного поводження з іншими ресурсами або для додатків спеціального використання, а не як засоби, які ваша програма використовує у звичайній роботі.


0

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

Не існує фіксованого часу, коли потрібно виконати фіналізатори, оскільки час виконання залежить від віртуальної машини Java (JVM). Єдина гарантія полягає в тому, що будь-який метод завершення роботи, який виконується, зробить це колись після того, як асоційований об'єкт стане недоступним (виявлений під час першого циклу вивезення сміття) і за якийсь час до того, як збирач сміття відновлює сховище відповідного об'єкта (під час другого циклу збирача сміття) . Виконання фіналізатора об'єкта може затягнутися довільно довгий час після того, як об'єкт стає недосяжним. Отже, виклик критично важливих для часу функцій, таких як закриття ручок файлів у методі finalize () об'єкта, є проблематичним.


-3

Спробуйте запустити цю програму для кращого розуміння

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();
            }
     }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.