Это затронет только небольшую часть пользователей, но я бы хотел, чтобы это было документировано для этой небольшой части. Из-за этой проблемы этот член этой маленькой горстки потратил 6 часов на устранение неполадок с работающим PHP-почтовым скриптом.
Если вы собираетесь в университет, в котором работает XAMPP с сайта www.AceITLab.com, вы должны знать, что наш профессор не сказал нам: брандмауэр AceITLab (а не брандмауэр Windows) блокирует MercuryMail в XAMPP , Вам придется использовать альтернативный почтовый клиент, груша работает на нас. Вам нужно будет отправить учетную запись Gmail с низкими настройками безопасности.
Да, я знаю, это абсолютно бесполезно для электронной почты реального мира. Однако, из того, что я видел, академические настройки и реальный мир часто имеют очень мало общего.
В общем, лучше не полагаться на finalize()
, чтобы делать очистку и т. д.
Согласно Javadoc (что было бы полезно прочитать), это :
Вызывается сборщиком мусора на объекте, когда сбор мусора определяет, что больше нет ссылок на объект.
Как указал Йоахим, это может никогда не произойти в жизни программы, если объект всегда доступен.
Кроме того, сборщик мусора не может запускаться в любое конкретное время. В общем, то, что я пытаюсь сказать,
finalize()
, вероятно, не самый лучший метод для использования вообще, если для этого не требуется что-то конкретное.
Иногда, когда он уничтожается, объект должен совершить действие. Например, если объект имеет не-java-ресурс, такой как дескриптор файла или шрифт, вы можете проверить, освобождены ли эти ресурсы до уничтожения объекта. Для управления такими ситуациями java предлагает механизм, называемый «финализация». Завершая его, вы можете определить конкретные действия, которые происходят, когда объект собирается быть удален из сборщика мусора. Чтобы добавить финализатор в класс, просто определите метод finalize (). Время выполнения Java вызывает этот метод всякий раз, когда он собирается удалить объект этого класса. В рамках метода finalize () вы указываете действия, которые необходимо выполнить перед уничтожением объекта. Сборщик мусора периодически ищет объекты, которые больше не ссылаются ни на какое рабочее состояние, ни косвенно на любой другой объект со ссылкой. Перед выпуском актива среда выполнения Java вызывает метод finalize () объекта. Метод finalize () имеет следующий общий вид:
protected void finalize(){
// This is where the finalization code is entered
}
С ключевым словом protected доступ к finalize () кодом вне его класса. Важно понимать, что finalize () вызывается непосредственно перед сборкой мусора. Он не вызывается, когда объект выходит из области, например. Это означает, что вы не можете знать, когда, или, если будет выполнен finalize () . В результате программа должна предоставлять другие средства для освобождения системных ресурсов или других ресурсов, используемых объектом. Вы не должны полагаться на finalize () для нормальной работы программы.
метод finalize не гарантируется. Этот метод вызывается, когда объект становится подходящим для 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, поскольку «Вызывается метод завершения в классе Bike ... "не печатается.
System.gc();
не является гарантией того, что сбор мусора будет фактически запущен.
– Simon Forsberg
21 September 2015 в 08:31
Объект становится пригодным для сбора мусора или GC, если его невозможно достичь из любых живых потоков или любых статических рефренсов, другими словами, вы можете сказать, что объект становится пригодным для сбора мусора, если все его ссылки равны нулю. Циклические зависимости не считаются ссылкой, поэтому, если объект А имеет ссылку на объект B, а объект B имеет ссылку на объект A, и у них нет другой живой ссылки, то оба объекта A и B будут иметь право на сбор мусора. Как правило, объект становится пригодным для сбора мусора в Java в следующих случаях:
final
объекта используется неоднократно во время медленного вычисления, и объект никогда не будет использоваться после этого, будет ли объект сохранен в живых до тех пор, пока последний код не запросит это поле, или может JIT-копия поле во временную переменную, а затем отказаться от объекта перед вычислением?
– supercat
27 April 2017 в 16:23
GC.KeepAlive()
, которая ничего не делает, заставляя GC предполагать, что она может использовать объект, но я не знаю такой функции в Java. Для этой цели можно использовать переменную volatile
, но использование переменной исключительно для такой цели представляется расточительным.
– supercat
4 May 2017 в 16:28
FinalizerReference
, чтобы он не нуждался в цикле GC, чтобы узнать, что ссылок нет. Синхронизация достаточно для обеспечения отношения происходит до i>; поскольку финализация может (фактически) работать в другом потоке, она часто формально необходима в любом случае. Java 9 добавит Reference.reachabilityFence
...
– Holger
4 May 2017 в 17:29
Finalize
будет вызван вообще, если бы JIT создал код, который сделал это напрямую. Предполагается ли, что код синхронизации будет ожидаться для объектов, которые ожидаются только в одном потоке? Если объект выполняет какие-либо действия, которые необходимо отменить, прежде чем он будет оставлен (например, открытие соединения сокета и получение эксклюзивного использования ресурса на другом конце), финализатор закрывает соединение, в то время как код по-прежнему использует сокет, будет катастрофой , Было бы нормально, если бы код использовал синхронизацию ...
– supercat
4 May 2017 в 18:42
finalize()
вызывается непосредственно перед сборкой мусора. Он не вызывается, когда объект выходит за рамки. Это означает, что вы не можете знать, когда или даже если будет выполняться finalize()
.
Пример:
Если ваша программа заканчивается перед сборщиком мусора, тогда 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();
}
}
}
Java позволяет объектам реализовать метод finalize (), который может быть вызван.
метод finalize () вызывается, если сборщик мусора пытается собрать объект.
Если сборщик мусора не запускается, метод не вызывается.
Если сборщик мусора не может собрать объект и пытается запустить его снова, метод не будет вызван в во второй раз.
На практике вы вряд ли сможете использовать его в реальных проектах.
Просто имейте в виду, что он не может быть вызван и что он определенно не будет дважды. Метод finalize () может начинаться с нуля или один раз.
В следующем коде метод finalize () не выводит результат, когда мы запускаем его с момента выхода программы, прежде чем возникнет необходимость запуска сборщика мусора.
Метод finalize
вызывается, когда объект собирается собирать мусор. Это может быть в любое время после того, как оно стало пригодным для сбора мусора.
Обратите внимание, что вполне возможно, что объект никогда не получает сбор мусора (и, таким образом, finalize
никогда не вызывается). Это может произойти, когда объект никогда не станет подходящим для gc (поскольку он доступен на протяжении всего жизненного цикла JVM) или когда сбор мусора фактически не выполняется между временем, когда объект становится приемлемым, и временем, когда JVM перестает работать (это часто происходит с простым тестовые программы).
Есть способы сообщить JVM запустить finalize
на объектах, на которые он еще не был вызван, но использовать их также не очень хорошо (гарантии этого метода также не очень сильны).
Если вы полагаетесь на finalize
для правильной работы вашего приложения, то вы делаете что-то неправильно. finalize
следует использовать только для очистки (обычно не Java) ресурсов. И это точно , потому что JVM не гарантирует, что finalize
когда-либо вызывается на любом объекте.
Closable
(и идея за ним), вероятно, вы хотите: make .close()
закрыть / отменить ресурс и потребовать от пользователя вашего класса позвонить ему в нужное время. Вы могли бы i> хотеть добавить метод finalize
"только для сохранения", но это будет скорее инструмент отладки, чем фактическое исправление (потому что оно недостаточно надежное).
– Joachim Sauer
13 June 2014 в 12:27
В последнее время борясь с методами финализатора (чтобы избавиться от пулов соединений во время тестирования), я должен сказать, что финализатору не хватает многих вещей. Используя VisualVM для наблюдения, а также используя слабые ссылки для отслеживания фактического взаимодействия, я обнаружил, что в среде Java 8 выполняются следующие вещи (Oracle JDK, Ubuntu 15):
Final Thought
Метод 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 будет распечатывать счетчик для создания класса.
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
Выйти Эффективная Java, страница 2-го издания 27. Пункт 7: Избегайте финализаторов
Финализаторы непредсказуемы, часто опасны и вообще не нужны. никогда не делайте ничего критически важного в финализаторе. никогда не зависеть от финализатора, чтобы обновить критическое постоянное состояние.
blockquote>Чтобы завершить работу ресурса, вместо этого используйте try-finally:
blockquote>// 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()
не является деструктором и не должен использоваться для обработки логики, от которой зависит ваше приложение. Спецификация Java заявляет, что нет гарантии, что метод finalize
вызывается вообще во время жизни приложения.
То, что вы, вероятно, хотите, это комбинация finally
и метода очистки, как в :
MyClass myObj;
try {
myObj = new MyClass();
// ...
} finally {
if (null != myObj) {
myObj.cleanup();
}
}
Когда метод
blockquote>finalize()
вызывается в Java?Метод finalize вызывается после того, как GC обнаружит, что объект больше недоступен, и до того, как он на самом деле восстанавливает память, используемую объектом.
- Если объект никогда не становится недоступным,
finalize()
никогда не будет вызываться на нем.- Если GC не запускается,
finalize()
никогда не может быть вызвана. (Обычно GC работает только тогда, когда JVM решает, что, вероятно, будет достаточно мусора, чтобы сделать его стоящим.)- Может потребоваться более одного цикла GC до того, как GC определит, что конкретный объект недоступен. (Java-GC, как правило, являются «генераторными» коллекторами ...)
- Как только GC обнаруживает, что объект недоступен и финализирован, он помещается в очередь финализации.
(Фактическая спецификация JVM позволяет JVM в never запускать финализаторы ... при условии, что что он не восстанавливает пространство, используемое объектами. JVM, который был реализован таким образом, будет искалечен / бесполезен, но это поведение «разрешено».)
В результате получается, что это неразумно полагаться на завершение, чтобы делать то, что нужно делать в определенные сроки. Это «лучшая практика», чтобы не использовать их вообще. Должен быть лучший (то есть более надежный) способ делать то, что вы пытаетесь сделать в методе
finalize()
.Единственное законное использование для финализации - очистка ресурсов, связанных с объектами, которые были потеряны кодом приложения. Даже тогда вы должны попытаться написать код приложения, чтобы он не потерял объекты в первую очередь. (Например, используйте Java 7+ try-with-resources , чтобы гарантировать, что
close()
всегда вызывается ...)
Я создал тест класс, который записывает в файл, когда метод finalize () вызывается путем его переопределения. Он не выполнен. Может ли кто-нибудь сказать мне причину, по которой он не выполняется?
blockquote>Трудно сказать, но есть несколько возможностей:
- Объект не
- Объект не собирает мусор, потому что GC не запускается до завершения вашего теста.
- Объект найден GC и помещен в завершение очереди GC, но до завершения теста завершение не завершено.
protected void finalize() throws Throwable {}
- каждый класс наследует метод
finalize()
из java.lang.Object- , метод вызывается сборщиком мусора, когда он не определяет больше ссылок на объект exist
- Метод finalize объекта не выполняет никаких действий, но может быть переопределен любым классом
- , как правило, он должен быть переопределен для очистки ресурсов, отличных от 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
Вы также можете проверить эту статью:
finalize
будет полезен? – nbro 21 May 2015 в 17:28finalize()
для основного класса вызывается, когда экземпляр & gt; & gt; & gt; & lt; класса - сбор мусора, а не когда основной метод завершается. И кроме того, основной класс мог i> собирать мусор до того, как приложение закончится; например в многопоточном приложении, где "основной" thread создает другие потоки, а затем возвращает. (На практике потребуется нестандартный загрузчик классов ....) – Stephen C 10 September 2016 в 07:51