Освобождается ли объектная память, когда мы явно вызываем для нее finalize ()?

Насколько я понимаю, finalize () и GC - это два разных аспекта. GC использует метод finalize () для освобождения памяти объекта. Мы не можем сказать, когда произойдет сборка мусора (даже если мы явно вызываем System.gc ()). Но мы можем явно вызвать finalize () для объекта.

Will the function be executed immediately(memory freed) or it waits till GC
occurs like System.gc() call?

Кроме того, согласно документации, метод finalize никогда не вызывается более одного раза виртуальной машиной Java для любого заданного объекта.

Итак, что происходит, когда мы сначала вызываем finalize (), а GC происходит позже.

If object memory is not freed on explicit call to object.finalize() then would't 
it being called again in the GC process violate the calling only once rule? 

person Aniket Thakur    schedule 29.08.2013    source источник
comment
@duffymo не совсем ...   -  person assylias    schedule 29.08.2013


Ответы (3)


Вы ошиблись.

Краткий ответ: finalize() - это средство очистки ресурсов (таких как открытые файлы) непосредственно перед тем, как объект будет готов для сборки мусора (когда ни один объект не имеет сильной ссылки на него). Это может / не называться. Это на шаг впереди процесса освобождения памяти.

Длинный ответ:

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

  1. При создании объекта JVM проверяет, не переопределил ли пользователь метод finalize (). Если это так, то он внутренне отмечает, что этот конкретный объект имеет метод finalize ().

Когда объект готов к сборке мусора, поток сборщика мусора проверяет, есть ли у этого конкретного объекта finalize () из таблицы, упомянутой в (1).

  • 2a) Если этого не произошло, он отправляется на сборку мусора.

    2b) Имеется, затем добавляется в очередь финализации. И удаляет запись объекта из таблицы (1).

Поток финализатора продолжает опрашивать очередь. Для каждого объекта в очереди вызывается его метод finalize (). После вызова finalize () цикл из (2) снова повторяется. Если этот объект по-прежнему не имеет сильной ссылки, отправляется в сборку мусора. Если это так, то ВСЕГДА вызывается (2a), потому что запись была удалена в (2b)

Basically finalize() method is only called once.

Так в чем же проблема с вышеуказанным циклом?

От 1). При создании объекта требуется дополнительное время. Выделение памяти в Java в 5-10 раз быстрее, чем у malloc / calloc и т. Д. Все выигранное время теряется на процедуру регистрации объекта в таблице и т. Д. Однажды я попробовал. Создайте 100000 объектов в цикле и измерьте время, необходимое для завершения программы в двух случаях: один без finalize (), второй с finalize (). Оказалось, что это на 20% быстрее.

Из (2b): Утечка памяти и голод. Если объект в очереди имеет ссылки на множество ресурсов памяти, то все эти объекты не будут освобождены, если этот объект не готов для сборки мусора. Если все объекты являются объектами с большим весом, то может быть нехватка.

Из (2b): Поскольку finalize () вызывается только один раз, что, если в finalize () у вас есть сильная ссылка на «этот» объект. В следующий раз, когда объект finalie () никогда не будет вызван, он может оставить объект в несогласованном состоянии.

Если внутри finalize () возникает исключение, оно игнорируется.

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

Следовательно, избегайте его использования. Вместо этого создайте метод say dispose (), который закроет необходимые ресурсы или для финального журнала и т. Д.

person Jatin    schedule 29.08.2013
comment
Таким образом, мы не можем явно вызвать finalize () для любого объекта, и даже если мы это сделаем, он будет выполняться только тогда, когда произойдет сборка мусора. Это правильно? - person Aniket Thakur; 29.08.2013
comment
Если хочешь позвонить, звони, всегда звони. Но это совсем не рекомендуется. И если вы его вызовете, он будет выполнен, как и любой другой вызов метода. GC вызывает его позже (хотя он может появиться, а может и не появиться). Подробнее читайте выше - person Jatin; 29.08.2013
comment
@Jatin - +1 (особенно за первое предложение), но, пожалуйста, просмотрите мою правку. Вы описали что finalize (), я объяснил, почему кто-то может подумать, что это им нужно. - person kdgregory; 29.08.2013
comment
Что означает утверждение «JVM проверяет, есть ли у объекта метод finalize ()»? Все объекты имеют метод finalize (), поскольку все они расширяют класс Object? - person Aniket Thakur; 29.08.2013
comment
Это означает, определили вы это явно или нет. Отредактировал это., - person Jatin; 29.08.2013
comment
В спецификации есть понятие «тривиального» финализатора, а именно: а) метод finalize(), объявленный java.lang.Object, б) пустой метод finalize() или в) метод finalize(), состоящий из единственного super.finalize() вызова другого тривиального метода финализации. Поэтому, когда объект создается, JVM проверяет, есть ли в его классе метод finalize, который является «нетривиальным». - person Holger; 07.09.2017
comment
@ Холгер Вау. Спасибо. Я не знал об этом факте. Я так много узнал из ваших ответов :). Спасибо! - person Jatin; 07.09.2017

Ответы в Object.finalize API

1) GC вызывает finalize (), поэтому finalize () и GC НЕ являются двумя разными аспектами

2) Вы не должны вызывать finalize вручную, но если вы это сделаете, это не освободит память и не повлияет на поведение GC.

3) Говорят, что гарантировано, что GC не вызовет finalize дважды, наши вызовы не учитываются

person Evgeniy Dorofeev    schedule 29.08.2013

Согласно документации:

Метод finalize никогда не вызывается виртуальной машиной Java более одного раза для любого заданного объекта.

Однако вы не можете принудительно запустить GC, вы можете просто спросить об этом через System.gc(). Поэтому лучший подход - поместить код, освобождающий ресурсы, в метод finalize() при переопределении.

person Juvanis    schedule 29.08.2013
comment
все еще зависит от jvm, но это в основном ответ - person Philipp Sander; 29.08.2013