Хотя вопрос был задан о методе Object.finalize
, речь в действительности идет о механизме финализации в целом. Этот механизм включает в себя не только API поверхности Object.finalize
, но также спецификации языка программирования о жизненном цикле объектов и практическое влияние на реализацию сборщика мусора в JVM.
Много было написано о том, почему финализация трудна в использовании с точки зрения приложения. См. Вопросы Зачем вам реализовывать finalize ()? и Следует ли отдавать предпочтение Java 9 Cleaner перед финализацией? и их ответами. См. Также Эффективная Java, 3-е издание Джошуа Блоха, пункт 8.
Вкратце, некоторые моменты о проблемах, связанных с использованием финализаторов:
общеизвестно, что их трудно правильно программировать
в частности, они могут неожиданно запускаться, когда объект
потому что недоступно неожиданно (но правильно); например,
см. мой ответ на этот вопрос
финализация может легко нарушить отношения подкласс / суперкласс
среди финализаторов нет порядка
метод данного объекта finalize
вызывается JVM не более одного раза, даже если этот объект "воскрес"
нет никаких гарантий относительно своевременности завершения или
даже то, что он вообще будет работать
нет явного механизма регистрации или отмены регистрации
Выше приведены трудности с использованием финализации. Любой, кто рассматривает возможность использования финализации, должен пересмотреть вопрос, учитывая приведенный выше список вопросов. Но достаточно ли этих проблем, чтобы отказаться от завершения в платформе Java? В следующих разделах объясняется несколько дополнительных причин.
Финализация потенциально делает системы хрупкими
Даже если вы напишите объект, который правильно использует финализацию, это может вызвать проблемы, когда ваш объект интегрирован в большую систему. Даже если вы вообще не используете финализацию, интеграция в большую систему, некоторые части которой используют финализацию, может привести к проблемам. Общая проблема заключается в том, что рабочие потоки, которые создают мусор, должны быть сбалансированы с сборщиком мусора. Если сборщик мусора отстает, по крайней мере, некоторые сборщики могут «остановить мир» и сделать полную сборку, чтобы наверстать упущенное. Завершение усложняет это взаимодействие. Даже если сборщик мусора идет в ногу с потоками приложений, финализация может привести к появлению узких мест и замедлению работы системы, а также может привести к задержкам в освобождении ресурсов, что приведет к исчерпанию этих ресурсов. Это проблема systems . Даже если фактический код, использующий финализацию, является правильным, проблемы все равно могут возникать в правильно запрограммированных системах.
Завершение способствует проблемам безопасности
Стандарт кодирования Oracle SEI CERT для Java содержит правило MET12-J: не использовать финализаторы . (Обратите внимание, это сайт о безопасном кодировании.) В частности, там написано
Неправильное использование финализаторов может привести к воскрешению объектов, готовых к сборке мусора, и к уязвимостям отказа в обслуживании.
Oracle Руководство по безопасному кодированию для Java SE более подробно описывает потенциальные проблемы безопасности, которые могут возникнуть при финализации. В этом случае это не проблема с кодом, который использует финализацию. Вместо этого злоумышленник может использовать финализацию для атаки на чувствительный код, который не защищен должным образом. В частности, Рекомендация 7-3 / OBJECT-3 частично заявляет,
Частично инициализированные экземпляры неконечного класса могут быть доступны через атаку финализатора.Атакующий переопределяет защищенный метод finalize
в подклассе и пытается создать новый экземпляр этого подкласса.Эта попытка не удалась ... но злоумышленник просто игнорирует любое исключение и ожидает, пока виртуальная машина выполнит финализацию на частично инициализированном объекте.Когда это происходит, вызывается реализация вредоносного метода finalize
, предоставляя злоумышленнику доступ к this
, ссылке на завершаемый объект.Хотя объект инициализируется только частично, злоумышленник может вызывать методы для него ....
Таким образом, наличие механизма финализации в платформе накладывает бремя на программистов, которые пытаются писатькод высокой надежности.
Завершение добавляет сложности к спецификациям
Платформа Java определяется несколькими спецификациями, включая спецификации языка, виртуальной машины и библиотеки классов.API-интерфейсы.Воздействие финализации тонко распределено по всем этим, но оно постоянно дает о себе знать.Например, финализация имеет очень тонкое взаимодействие с созданием объекта (которое уже достаточно сложно).Финализация также появилась в открытых API Java, что означает, что развитие этих API (до сих пор) было обязано оставаться совместимым с ранее заданным поведением.Развитие этих спецификаций становится более дорогостоящим при наличии финализации.
Финализация добавляет сложности к реализациям
Это в основном касается сборщиков мусора.Существует несколько реализаций сборки мусора, и все они обязаны оплачивать стоимость реализации финализаций.Реализации довольно хороши в минимизации накладных расходов времени выполнения, если финализация не используется.Однако реализация все еще должна быть там, и она должна быть правильной и хорошо протестированной.Это постоянное бремя разработки и обслуживания.
Резюме
В других местах мы видели, что программистам не рекомендуется использовать финализацию.Однако, если что-то бесполезно, это не обязательно означает, что это следует считать устаревшим.Приведенные выше пункты иллюстрируют тот факт, что даже если финализация не используется, простое присутствие механизма в платформе влечет за собой постоянные затраты на спецификацию, разработку и обслуживание.Ввиду недостаточной полезности механизма и затрат, которые он налагает, имеет смысл отказаться от него.В конце концов, избавление от финализации пойдет на пользу всем.
На момент написания этой статьи (2019-06-04) нет конкретного плана по удалению финализации из Java.Тем не менее, это, безусловно, намерение сделать это.Мы устарели Object.finalize
, но не отметили его для удаления.Это официальная рекомендация, чтобы программисты прекратили использовать этот механизм.Неформально известно, что финализация не должна использоваться, но, конечно, необходимо сделать формальный шаг.Кроме того, некоторые finalize
методы в библиотечных классах (например, ZipFile.finalize
) объявлены устаревшими «для удаления», что означает, что поведение финализации этих классов может быть удалено из будущего выпуска.В конце концов мы надеемся отключить финализацию в JVM (возможно, сначала по желанию, а затем по умолчанию) и в какой-то момент в будущем фактически удалить реализацию финализации из сборщиков мусора.