From 6666fbb89564e94f621ae536b1e68b5b072da3e1 Mon Sep 17 00:00:00 2001 From: Arthur Date: Tue, 17 Mar 2020 16:55:32 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=20=D0=BF=D1=80=D0=B8=D0=BC=D0=B5=D1=80=20=D0=B4=D0=BB?= =?UTF-8?q?=D1=8F=20finalize()?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- core.md | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-) diff --git a/core.md b/core.md index 12fafe6..1933d8f 100644 --- a/core.md +++ b/core.md @@ -773,12 +773,80 @@ __Пул строк__ – это набор строк хранящийся в _ [к оглавлению](#java-core) ## Что такое `finalize()`? Зачем он нужен? -Через вызов метода `finalize()` JVM реализуется функциональность аналогичная функциональности деструкторов в С++, используемых для очистки памяти перед возвращением управления операционной системе. Данный метод вызывается при уничтожении объекта сборщиком мусора (_garbage collector_) и переопределяя `finalize()` можно запрограммировать действия необходимые для корректного удаления экземпляра класса - например, закрытие сетевых соединений, соединений с базой данных, снятие блокировок на файлы и т.д. +Через вызов метода `finalize()` (который наследуется от Java.lang.Object) JVM реализуется функциональность аналогичная функциональности деструкторов в С++, используемых для очистки памяти перед возвращением управления операционной системе. Данный метод вызывается при уничтожении объекта сборщиком мусора (_garbage collector_) и переопределяя `finalize()` можно запрограммировать действия необходимые для корректного удаления экземпляра класса - например, закрытие сетевых соединений, соединений с базой данных, снятие блокировок на файлы и т.д. После выполнения этого метода объект должен быть повторно собран сборщиком мусора (и это считается серьезной проблемой метода `finalize()` т.к. он мешает сборщику мусора освобождать память). Вызов этого метода не гарантируется, т.к. приложение может быть завершено до того, как будет запущена сборка мусора. Объект не обязательно будет доступен для сборки сразу же - метод `finalize()` может сохранить куда-нибудь ссылку на объект. Подобная ситуация называется «возрождением» объекта и считается антипаттерном. Главная проблема такого трюка - в том, что «возродить» объект можно только 1 раз. +Пример: +```java +public class MainClass { + + public static void main(String args[]) { + TestClass a = new TestClass(); + a.a(); + a = null; + a = new TestClass(); + a.a(); + System.out.println("!!! done"); + } +} +``` +```java + +public class TestClass { + + public void a() { + System.out.println("!!! a() called"); + } + + @Override + protected void finalize() throws Throwable { + System.out.println("!!! finalize() called"); + super.finalize(); + } +} +``` +Так как в данном случае сборщик мусора может и не быть вызван (в силу простоты приложения), то результат выполнения программы с большой вероятностью будет следующий: +``` +!!! a() called +!!! a() called +!!! done +``` +Теперь несколько усложним программу, добавив принудительный вызов Garbage Collector: +```java +public class MainClass { + + public static void main(String args[]) { + TestClass a = new TestClass(); + a.a(); + a = null; + System.gc(); // Принудительно зовём сборщик мусора + a = new TestClass(); + a.a(); + System.out.println("!!! done"); + } + +} +``` +Как и было сказано ранее, Garbage Collector может в разное время отработать, поэтому результат выполнения может разниться от запуска к запуску: +Вариант а: +``` +!!! a() called +!!! a() called +!!! done +!!! finalize() called +``` +Вариант б: +``` +!!! a() called +!!! a() called +!!! finalize() called +!!! done +``` + + [к оглавлению](#java-core) ## Что произойдет со сборщиком мусора, если выполнение метода `finalize()` требует ощутимо много времени, или в процессе выполнения будет выброшено исключение?