Во время написания статьи про использование фантомных ссылок, мне потребовалось сослаться на неудобства возникающие при работе с методом finalize. К тому же, считаю, что данный топик будет полезен всем начинающим java разработчикам, а некоторые пункты будет не лишним вспомнить и матерым программистам, ведь использовать метод finalize очень просто, чего не скажешь о поиске последсвий этого. Даже если вы твердо убеждены никогда не использовать метод finalize, это еще не значит, что ваши предыдущие коллеги их не использовали, и вам не надо понимать как они работают.
Итак, поехали от очевидного к менее интуитивному.
Согласно всему вышесказанному по возможности следует избегать использование метода finalize, вернее не стоит полагаться на него. Лучше освобождать ресурсы программно, а в методе finalize логировать, если этого почему-то сделано не было, чтобы вовремя найти и починить возникшую проблему.
Если же вам все же надо освободить ресурсы именно при сборке объекта, то, вероятнее всего для этого лучше использовать фантомные ссылки.
Итак, поехали от очевидного к менее интуитивному.
- Так как метод finalize вызывается при первой сборке мусора следующей за моментом когда ваш объект стал недостижим, то вполне реально, что он не будет вызван вообще, ведь ваше приложение може�� закончить свою работу так и не дойдя до этой самой сборки мусора. Хотя, конечно, есть один замечательный метод System.runFinalizersOnExit(true), вызвав который на старте программы, метод finalize все таки сработает у уже недостижимых объектах во время корректной остановки приложения.
- Спецификация JVM не определяет вопрос многопоточности метода финализации. В HotSpot все методы finalize будут вызываться последовательно в одном потоке Finalizer. Однако, если вы вызовете метод System.runFinalization(), то родится еще один поток, который заблокирует текущий и будет выполнять методы finalize, если подходящие объекты есть в очереди. Причем это вполне может происходить параллельно основному потоку Finalizer.
- Переопределение метода finalize значительно удлиняет время жизни объекта после смерти, так как он будет удален из памяти не раньше второй сборки мусора. А учитывая два первых пункта, если метод finalize у вас будет тяжелым и\или таких объектов будет очень много, то объекты могут довольно долго висеть в фазе финализации и продолжать занимать место в памяти.
- Во время выполнения метода finalize вы можете восстановить ссылку на объект, например, поместив ее в какой-нибудь статический контекст, тем самым вы воскресите объект. Опасность такого маневра заключается в том, что второй раз метод finalize у данного объекта уже никогда вызван не будет. Поэтому если вам по каким-то причинам очень надо воскресить данный объект, то лучше создавайте внутри метода finalize его копию.
- Одна из самых неприятных проблем возникающих при использовании метода finalize — это реордеринг. Представьте, что у вас есть два объекта с переопределенным методом finalize, один из которых ссылается на другой. Так вот, если эти объекты стали недостижимы, то порядок вызова методов финализации произойдет в случайном порядке. Таким образом, у вас будет потенциальная опасность вызвать какой-нибудь метод на уже финализированном объекте из метода finalize другого объекта и получить ошибку. Причем проблема будет возникать не на каждом объекте, что добавит головной боли при отладке.
- Согласно Джошуа Блоху, автору знаменитой книги «Effective Java: Programming Language Guide», для объектов с переопределенным методом finalize аллокация и сборка может происходить в 430 раз медленнее, чем у обычного объекта.
- Любые исключения выброшенные в теле метода будут проигнорированы.
- Надо не забыть в конце метода вызвать super.finalize (). А учитывая предыдущий пункт, сделать это необходимо в блоке finally.
Согласно всему вышесказанному по возможности следует избегать использование метода finalize, вернее не стоит полагаться на него. Лучше освобождать ресурсы программно, а в методе finalize логировать, если этого почему-то сделано не было, чтобы вовремя найти и починить возникшую проблему.
Если же вам все же надо освободить ресурсы именно при сборке объекта, то, вероятнее всего для этого лучше использовать фантомные ссылки.
