Согласно «Эффективной Java» Джошуа Блоха (второе издание), есть два сценария, когда finalize()
это полезно:
Один из них - действовать как «сеть безопасности» на случай, если владелец объекта забудет вызвать его явный метод завершения. Хотя нет гарантии, что финализатор будет вызван быстро, может быть лучше освободить ресурс поздно, чем никогда, в тех (надеюсь, редких) случаях, когда клиенту не удается вызвать явный метод завершения. Но финализатор должен записать предупреждение, если обнаружит, что ресурс не был прерван
Второе законное использование финализаторов касается объектов с нативными пирами. Собственный узел - это нативный объект, которому нормальный объект делегирует нативные методы. Поскольку нативный узел не является нормальным объектом, сборщик мусора не знает об этом и не может вернуть его, когда его Java-узел исправлен. Финализатор является подходящим средством для выполнения этой задачи, при условии, что у нативного партнера нет критических ресурсов. Если собственный одноранговый узел содержит ресурсы, которые должны быть немедленно завершены, у класса должен быть явный метод завершения, как описано выше. Метод завершения должен делать все, что требуется для освобождения критического ресурса.
Для дальнейшего чтения обратитесь к пункту 7, стр. 27.
Финализаторы важны для управления нативными ресурсами. Например, вашему объекту может потребоваться выделить WidgetHandle из операционной системы, используя не-Java API. Если вы не выпустите этот WidgetHandle, когда ваш объект GC'd, вы будете пропускать WidgetHandles.
Важно то, что случаи "финализатор никогда не вызывается" разбиваются довольно просто:
Во всех этих трех случаях у вас либо нет собственной утечки (в силу того факта, что ваша программа больше не работает), либо у вас уже есть несобственная утечка (если вы продолжаете выделять управляемые объекты без их GC'd).
Предупреждение «не полагайтесь на вызываемый финализатор» на самом деле означает не использовать финализаторы для логики программы. Например, вы не хотите отслеживать, сколько ваших объектов существует во всех экземплярах вашей программы, увеличивая счетчик в файле где-то во время построения и уменьшая его в финализаторе - потому что нет гарантии, что ваши объекты будут В конечном итоге этот счетчик файлов, вероятно, никогда не вернется к 0. Это действительно особый случай более общего принципа, согласно которому вы не должны зависеть от нормального завершения вашей программы (сбой питания и т. д.).
Однако для управления собственными ресурсами случаи, когда финализатор не запускается, соответствуют случаям, когда вам все равно, не запускается ли он.
источник
close()
выполняется ( никогда не вызывается до того, как он станет недоступным)Назначение этого метода объясняется в документации API следующим образом:
Если вас дополнительно интересуют причины, по которым разработчики языка выбрали тот «объект, который безвозвратно отбрасывается» ( сборщик мусора ), выходящий за пределы контроля программиста приложения («мы никогда не должны полагаться»), это было объяснено в ответе на вопрос :
Выше цитата, в свою очередь, была взята из официальной документации о целях разработки Java , то есть ее можно считать авторитетным справочным материалом, объясняющим, почему разработчики языка Java решили так.
Более подробное и независимое от языка обсуждение этого предпочтения см. В разделе 9.6 «Автоматическое управление памятью» в OOSC (на самом деле, не только этот раздел, но и целую главу 9 очень стоит прочитать, если вы заинтересованы в подобных вещах). Этот раздел открывается однозначным утверждением:
источник
Финализаторы существуют потому, что от них ожидали, что они станут эффективным средством обеспечения очистки вещей (даже если на практике это не так), а также потому, что когда они были изобретены, это лучшее средство обеспечения очистки (например, фантомные ссылки и пробная версия). -ресурсы) еще не существовало. Оглядываясь назад, Java, вероятно, был бы лучше, если бы усилия, потраченные на реализацию его средства «финализации», были потрачены на другие средства очистки, но это было едва ли понятно во время первоначальной разработки Java.
источник
ПРЕДУПРЕЖДЕНИЕ: Я могу быть устаревшим, но это мое понимание несколько лет назад:
В общем, нет никакой гарантии того, что финализатор запущен - или даже вообще запущен, хотя некоторые JVM позволяют запрашивать полный GC и финализацию до выхода из программы (что, конечно, означает, что программа занимает больше времени) выйти, и который не является режимом работы по умолчанию).
И некоторые GC, как известно, явно задерживают или избегают GC'ing объектов, которые имеют финализаторы, в надежде, что это даст лучшую производительность в тестах.
К сожалению, такое поведение противоречит первоначальным причинам, по которым были рекомендованы финализаторы, и поощряет использование явно вызываемых методов завершения работы.
Если у вас есть объект, который действительно нужно очистить перед тем, как выбросить, и если вы действительно не можете доверять пользователям это, финализатор все же стоит рассмотреть. Но в целом, есть веские причины, по которым вы не видите их в современном Java-коде так часто, как в некоторых ранних примерах.
источник
В Руководстве по стилю Google Java есть несколько мудрых советов по этому вопросу:
источник
PhantomReference
иReferenceQueue
вместо нее .PhantomReference
, это лучшее решение. Финализаторы - это бородавка, оставшаяся с первых дней Java, и подобныеObject.clone()
и необработанные типы являются частью языка, о котором лучше всего забыть.Спецификация языка Java (Java SE 7) гласит:
источник