Когда в Java вызывается метод finalize ()?
Ответы (17)
В общем, лучше не полагаться на finalize()
при очистке и т. Д.
Согласно Javadoc (который стоило бы прочитать), это:
Вызывается сборщиком мусора для объекта, когда сборщик мусора определяет, что на этот объект больше нет ссылок.
Как указал Иоахим, этого может никогда не случиться в жизни программы, если объект всегда доступен.
Кроме того, сборщик мусора не может быть запущен в определенное время. В общем, то, что я пытаюсь сказать, finalize()
, вероятно, не лучший метод для использования в целом, если нет чего-то конкретного, для чего он вам нужен.
finalize
может быть полезен?
- person nbro; 21.05.2015
finalize()
для основного класса вызывается при сборке мусора ›› экземпляр ‹< класса, а не при завершении работы основного метода. Кроме того, основной класс может быть собранным до завершения работы приложения; например в многопоточном приложении, где основной поток создает другие потоки, а затем возвращается. (На практике потребуется нестандартный загрузчик классов ....)
- person Stephen C; 10.09.2016
Метод finalize
вызывается, когда объект собирается получить сборщик мусора. Это может произойти в любое время после того, как он получит право на сборку мусора.
Обратите внимание: вполне возможно, что объект никогда не получает сборщик мусора (и поэтому finalize
никогда не вызывается). Это может произойти, когда объект никогда не становится подходящим для gc (потому что он доступен в течение всего времени существования JVM) или когда сборка мусора фактически не выполняется между моментом, когда объект становится подходящим, и временем, когда JVM перестает работать (это часто происходит с простым тестовые программы).
Есть способы указать JVM запустить finalize
на объектах, которые еще не вызывались, но их использование тоже не очень хорошая идея (гарантии этого метода также не очень сильны).
Если вы полагаетесь на finalize
для правильной работы вашего приложения, значит, вы делаете что-то не так. finalize
следует только использовать для очистки ресурсов (обычно не связанных с Java). И это точно, потому что JVM не гарантирует, что finalize
когда-либо будет вызван для любого объекта.
Closable
(и идея, лежащая в его основе), вероятно, именно то, что вам нужно: заставить .close()
закрыть / отбросить ресурс и потребовать от пользователя вашего класса вызвать его в нужное время. Вы можете добавить метод finalize
просто для сохранения, но это будет скорее инструмент отладки, чем фактическое исправление (потому что он недостаточно надежен).
- person Joachim Sauer; 13.06.2014
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 < / а>
Вы также можете проверить эту статью:
Метод Java finalize()
не является деструктором и не должен использоваться для обработки логики, от которой зависит ваше приложение. В спецификации Java говорится, что нет никакой гарантии, что метод finalize
вообще будет вызван во время работы приложения.
Вероятно, вам нужна комбинация finally
и метода очистки, например:
MyClass myObj;
try {
myObj = new MyClass();
// ...
} finally {
if (null != myObj) {
myObj.cleanup();
}
}
Это правильно обработает ситуацию, когда конструктор MyClass()
выдает исключение.
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 }
Когда в Java вызывается метод
finalize()
?
Метод finalize будет вызываться после того, как сборщик мусора обнаружит, что объект больше недоступен, и до того, как он фактически освободит память, используемую объектом.
Если объект никогда не становится недоступным,
finalize()
никогда не будет вызван для него.Если GC не запускается, то
finalize()
может никогда не быть вызван. (Обычно сборщик мусора запускается только в том случае, если JVM решает, что мусора достаточно, чтобы его использовать.)Прежде чем сборщик мусора определит, что конкретный объект недоступен, может пройти несколько циклов сборки мусора. (Сборщики мусора Java обычно являются сборщиками "поколений" ...)
Как только сборщик мусора обнаруживает, что объект недоступен и может быть завершен, он помещается в очередь завершения. Завершение обычно происходит асинхронно с обычным сборщиком мусора.
(Спецификация JVM фактически позволяет JVM никогда запускать финализаторы ... при условии, что она не освобождает пространство, используемое объектами. JVM, которая была реализованный таким образом будет парализован / бесполезен, но если такое поведение «разрешено».)
В результате неразумно полагаться на финализацию, чтобы делать то, что нужно сделать в определенные сроки. Лучше всего их вообще не использовать. Должен быть лучший (то есть более надежный) способ делать то, что вы пытаетесь сделать в методе finalize()
.
Единственное законное использование финализации - очистка ресурсов, связанных с объектами, которые были потеряны кодом приложения. Даже в этом случае вы должны попытаться написать код приложения так, чтобы он вообще не терял объекты. (Например, используйте Java 7+ try-with-resources, чтобы гарантировать, что close()
всегда вызывается ...)
Я создал тестовый класс, который записывает в файл при вызове метода finalize () путем его переопределения. Не выполняется. Кто-нибудь может сказать мне причину, по которой он не выполняется?
Сложно сказать, но есть несколько возможностей:
- Объект не собирается сборщиком мусора, потому что он все еще доступен.
- Объект не собирается сборщиком мусора, потому что сборщик мусора не запускается до завершения теста.
- Объект находит сборщик мусора и помещает сборщик мусора в очередь финализации, но финализация не завершается до завершения вашего теста.
Поскольку существует неопределенность при вызове метода 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 ...» не печатается.
System.gc();
не гарантирует, что сборка мусора действительно будет запущена.
- person Simon Forsberg; 21.09.2015
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
В последнее время столкнувшись с методами финализатора (чтобы избавиться от пулов соединений во время тестирования), я должен сказать, что финализатору не хватает многих вещей. Используя VisualVM для наблюдения, а также используя слабые ссылки для отслеживания фактического взаимодействия, я обнаружил, что в среде Java 8 (Oracle JDK, Ubuntu 15) верны следующие вещи:
- Finalize не вызывается сразу, Finalizer (часть GC) неуловимо владеет ссылкой индивидуально
- Сборщик мусора по умолчанию объединяет недостижимые объекты
- Finalize вызывается массово, указывая на детали реализации, что существует определенная фаза, на которой сборщик мусора освобождает ресурсы.
- Вызов System.gc () часто не приводит к более частой финализации объектов, он просто приводит к тому, что Finalizer быстрее узнает о недоступном объекте.
- Создание дампа потока почти всегда приводит к запуску финализатора из-за высоких накладных расходов кучи во время выполнения дампа кучи или какого-либо другого внутреннего механизма.
- Швы финализации должны быть связаны либо требованиями к памяти (высвободить больше памяти), либо списком объектов, помеченных для завершения, ростом определенного внутреннего лимита. Поэтому, если у вас есть много завершаемых объектов, фаза завершения будет запускаться чаще и раньше по сравнению с несколькими.
- Были обстоятельства, что System.gc () запускал finalize напрямую, но только в том случае, если ссылка была локальной и недолговечной. Это может быть связано с поколением.
Последняя мысль
Метод Finalize ненадежен, но может использоваться только для одной цели. Вы можете гарантировать, что объект был закрыт или удален до того, как он был собран сборщиком мусора, что позволяет реализовать отказоустойчивость, если объекты с более сложным жизненным циклом, включающим действие по окончании срока службы, обрабатываются правильно. Это единственная причина, по которой я могу придумать, что стоит переопределить ее.
Объект получает право на сборку мусора или сборщик мусора, если он недоступен из каких-либо живых потоков или каких-либо статических ссылок, другими словами, вы можете сказать, что объект становится подходящим для сборки мусора, если все его ссылки равны нулю. Циклические зависимости не считаются ссылочными, поэтому, если объект A имеет ссылку на объект B, а объект B имеет ссылку на объект A и у них нет другой живой ссылки, тогда оба объекта A и B будут иметь право на сборку мусора. Обычно объект имеет право на сборку мусора в Java в следующих случаях:
- Все ссылки на этот объект явно имеют значение null, например. объект = ноль
- Объект создается внутри блока, и ссылка выходит за пределы области действия после выхода управления из этого блока.
- Для родительского объекта установлено значение null, если объект содержит ссылку на другой объект и когда вы устанавливаете нулевую ссылку на объект-контейнер, дочерний или содержащийся объект автоматически получает право на сборку мусора.
- Если объект имеет только живые ссылки через WeakHashMap, он будет иметь право на сборку мусора.
final
объекта используется повторно во время медленных вычислений, и объект никогда не будет использоваться после этого, будет ли объект оставаться активным до последнего запроса исходного кода поля, или JIT может скопировать поле в временная переменная, а затем отказаться от объекта перед вычислением?
- person supercat; 27.04.2017
GC.KeepAlive()
, которая ничего не делает, кроме как заставляет сборщик мусора предполагать, что он может использовать объект, но я не знаю такой функции в Java. Для этой цели можно использовать volatile
переменную, но использование переменной исключительно для этой цели было бы расточительным.
- person supercat; 04.05.2017
FinalizerReference
в очередь, чтобы не потребовался цикл GC, чтобы узнать, что есть нет ссылок. Синхронизации достаточно, чтобы гарантировать связь происходит до; поскольку финализация может (фактически выполняется) выполняться в другом потоке, это часто формально необходимо в любом случае. Java 9 собирается добавить _ 2_…
- person Holger; 04.05.2017
Finalize
будет вызван вообще, если JIT произвел код, который сделал бы это напрямую. Ожидается ли обычно код синхронизации для объектов, которые предполагается использовать только в одном потоке? Если объект выполняет какое-то действие, которое необходимо отменить, прежде чем он будет оставлен (например, открытие соединения с сокетом и получение исключительного права на использование ресурса на другом конце), то, что финализатор закроет соединение, пока код все еще использует сокет, будет катастрофой. . Было бы нормально, если бы код использовал синхронизацию ...
- person supercat; 04.05.2017
finalize()
. Но когда вы полагаетесь исключительно на неизменяемость для достижения этой потоковой безопасности, отсутствие явного использования объекта действительно может иметь катастрофические последствия. Это реальная проблема. Вот почему предпочтительнее использовать эталонный API; там у вас есть полный контроль над тем, когда и в каком потоке вы опрашиваете ReferenceQueue
для очистки ресурсов.
- person Holger; 05.05.2017
Метод finalize не гарантируется. Этот метод вызывается, когда объект становится подходящим для сборки мусора. Есть много ситуаций, когда объекты не могут быть обработаны сборщиком мусора.
Иногда при разрушении объект должен совершить действие. Например, если у объекта есть не-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 () для нормальной работы программы.
Класс, в котором мы переопределяем метод 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()
не будет выполняться. Следовательно, его следует использовать в качестве процедуры резервного копирования для обеспечения правильной обработки других ресурсов или для специальных приложений, а не в качестве средства, которое ваша программа использует в своей нормальной работе.
Как указано в https://wiki.sei.cmu.edu/confluence/display/java/MET12-J.+Do+not+use+finalizers,
Не существует фиксированного времени, в которое должны выполняться финализаторы, потому что время выполнения зависит от виртуальной машины Java (JVM). Единственная гарантия заключается в том, что любой выполняющийся метод финализатора сделает это через некоторое время после того, как связанный объект станет недоступным (обнаружен во время первого цикла сборки мусора) и где-то до того, как сборщик мусора освободит хранилище связанного объекта (во время второго цикла сборщика мусора). . Выполнение финализатора объекта может быть отложено на сколь угодно долгое время после того, как объект станет недоступным. Следовательно, вызов критических по времени функций, таких как закрытие дескрипторов файлов в методе finalize () объекта, является проблематичным.
Попробуйте запустить эту программу для лучшего понимания
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();
}
}
}
finalize()
и сборка мусора не оказывает никакого влияния. - person ha9u63ar   schedule 11.01.2018