(Этот вопрос отличается от Зачем вам когда-либо реализовывать finalize()?. Этот вопрос касается устаревания платформы Java, а другой вопрос касается того, следует ли использовать этот механизм в приложениях.)
Почему метод finalize() устарел в Java 9?
Да, это может быть использовано неправильно (например, сохранить объект от сборки мусора [только один раз] или попытаться закрыть некоторые нативные ресурсы внутри него [хотя это лучше, чем вообще не закрывать]), а также многие другие методы могли быть использованы неправильно.
Так действительно ли finalize() настолько опасен или абсолютно бесполезен, что его необходимо выкинуть из Java?
Короткий ответ, однако: да. Он бесполезен гораздо чаще, чем думают люди, опасен в использовании даже для экспертов, которые очень хорошо в нем разбираются (например, если вы не знаете, что такое ограждение достижимости и как его использовать, я гарантирую, что все ваши финализаторы, управляющие нативными ресурсами, глючит), и это привлекательная неприятность для тех, кто ищет деструкторы в стиле C++. Я говорю: прощайте финализаторы и скатертью дорога.
Ваш вопрос может отличаться, но отвечать один и тот же. (Вот почему сообщение сформулировано так: «На этот вопрос уже есть ответ здесь».) Если нет допустимого варианта использования, устаревание является естественным.
Вот ветка о том, чем его следует заменить: stackoverflow.com/questions/47762986/replacing-finalize-in-java
Хотя @DanielPryden уже объяснил, почему на самом деле не имеет значения, отличается ли ваш вопрос от дубликата, я бы также добавил, что ваш вопрос, вероятно, не соответствует теме переполнения стека, поскольку на самом деле он не касается проблемы программирования и любых ответов. будет «в основном основанный на мнении». (Я полагаю, вам могло невероятно повезти, и вы получили ответ от человека, ответственного за решение отказаться от поддержки finalize() в JDK 10, но это маловероятно, и любой другой ответ был бы просто предположением.)
@skomisa Жаль, что этот вопрос был закрыт. Существует ряд вопросов о обоснование для решений, на которые, безусловно, можно ответить. Либо люди, участвующие в решении, могут появиться и ответить на него — что, безусловно, случалось раньше, особенно в отношении недавних решений, — либо ответ может быть где-то записан, либо в сообщении списка рассылки, либо в комментарии в отчете об ошибке. . Обоснование может быть субъективным, но оно может быть окончательным и не основанным исключительно на мнении.
@DanielPryden Вы не знаете, что ответ тот же, если только вы не участвовали в принятии решения. Я был; Я не думаю, что ты был.
@StuartMarks: Вы, конечно, правы. Единственное, что я знаю о причинах, это то, что находится в открытом доступе в архивах списков рассылки. Если вы чувствуете, что на вопрос можно дать осмысленный ответ, не превращаясь в повторение того, почему финализаторы проблематичны, у меня нет возражений. Я воздержусь от дальнейших действий по этому вопросу; пожалуйста, проголосуйте за повторное открытие, если хотите. Я признаю, что частью моего стремления закрыть вопрос является несколько разглагольствованная природа формулировки («Так действительно ли метод finalize() настолько опасен или абсолютно бесполезен, чтобы выкинуть его из Java?»).
@StuartMarks: Как бы то ни было, поскольку у вас есть золотой значок в теге java, вы можете в одиночку повторно открыть вопрос, если считаете, что он должен быть открытым.
@DanielPryden Спасибо за ваши ответы. Un-dupe-молоток работает! Я этого не знал. Я знал о двойном молотке, но я, кажется, помню, что мне приходилось голосовать и ждать других голосов, чтобы снова открыть закрытые вопросы в прошлом. В любом случае я дам ответ в какой-то момент.
@StuartMarks Что ж, я, безусловно, понимаю вашу (подразумеваемую) точку зрения о том, что, поскольку вы участвовали в принятии решения о прекращении поддержки Object.finalize(), может иметь смысл снова открыть это, как было предложено в другом комментарии. Я предполагаю, что Object.finalize(), возможно, был объявлен устаревшим специально в Java 9 (в отличие от любого более раннего/позднего выпуска) из-за добавления класса Cleaner в Java 9, и JDK-8165641 Устаревший Object.finalize несколько поддерживает эту точку зрения, но это просто предположение с моей стороны. В любом случае, голосование за возобновление работы на основе ваших комментариев.
@StuartMarks Хех - я вижу, что вопрос был вновь открыт, пока я писал свой комментарий.
@skomisa Да, Дэниел Прайден указал мне, что я могу сделать это сам, что я и сделал! В любом случае, спасибо за ваш ответ. Я думаю, что есть что сказать, чего нет в другом ответе. Извините, я был немного резок по этому поводу - я действительно думаю, что вопросы об обосновании отличаются от чисто «основанных на мнении» вопросов, таких как «Является ли X лучше, чем Y?» и что можно получить полезные (хотя и субъективные) ответы о логическом обосновании.
@StuartMarks [1] Я согласен со всем этим, и, оглядываясь назад, я явно поторопился, предположив, что маловероятно, чтобы кто-либо, участвовавший в решении отказаться от поддержки finalize(), ответил здесь - мой плохой. [2] Хотя это и не дубликат, Следует ли предпочесть Java 9 Cleaner финализации? кажется уместным.
@skomisa (Ах, это основано на закрытом мнении, где мне пришлось ждать повторного открытия голосования, тогда как это было повторно открыто немедленно, потому что оно было закрыто как дубликат. Я перепутал их.) В любом случае, может быть, я тоже снова открыл быстро, потому что этот вопрос теперь, кажется, привлекает плохие ответы!




Хотя вопрос был о методе Object.finalize, на самом деле речь идет о механизме завершение в целом. Этот механизм включает в себя не только поверхностный API Object.finalize, но также включает спецификации языка программирования о жизненном цикле объектов и практическое влияние на реализацию сборщиков мусора в JVM.
Много было написано о том, почему финализацию трудно использовать с точки зрения приложения. См. вопросы Зачем вам когда-либо реализовывать finalize()? и Следует ли предпочесть Java 9 Cleaner финализации? и ответы на них. См. также Эффективная Java, 3-е издание Джошуа Блоха, пункт 8.
Вкратце, некоторые моменты о проблемах, связанных с использованием финализаторов:
их, как известно, трудно правильно запрограммировать
в частности, они могут запускаться неожиданно, когда объект становится недостижимым неожиданно (но правильно); Например, см. мой ответ на этот вопрос
финализация может легко нарушить отношения подкласса/суперкласса
нет порядка среди финализаторов
метод finalize данного объекта вызывается JVM не более одного раза, даже если этот объект «воскрес»
отсутствуют гарантии своевременности доработки или даже то, что он будет работать вообще
нет явного механизма регистрации или отмены регистрации
Выше перечислены сложности с использованием финализации. Любой, кто рассматривает возможность использования финализации, должен пересмотреть свое решение, учитывая приведенный выше список проблем. Но достаточно ли этих проблем, чтобы отказаться от финализации на платформе Java? Есть несколько дополнительных причин, описанных в разделах ниже.
Завершение потенциально делает системы хрупкими
Даже если вы пишете объект, который правильно использует завершение, это может вызвать проблемы, когда ваш объект интегрируется в более крупную систему. Даже если вы вообще не используете финализацию, интеграция в более крупную систему, некоторые части которой используют финализацию, может привести к проблемам. Общая проблема заключается в том, что рабочие потоки, создающие мусор, должны быть сбалансированы со сборщиком мусора. Если сборщик мусора отстает, по крайней мере, некоторые сборщики могут «остановить мир» и выполнить полную сборку, чтобы наверстать упущенное. Финализация усложняет это взаимодействие. Даже если сборщик мусора успевает за потоками приложения, финализация может создать узкие места и замедлить работу системы или вызвать задержки в освобождении ресурсов, что приведет к исчерпанию этих ресурсов. Это проблема системы. Даже если фактический код, использующий финализацию, правильный, в правильно запрограммированных системах все равно могут возникать проблемы.
(Правка 2021-09-16: этот вопрос описывает проблему, когда система нормально работает при низкой нагрузке, но дает сбой при высокой нагрузке, вероятно, потому, что относительная скорость выделения превышает скорость завершения при высокой нагрузке.)
Завершение способствует проблемам безопасности
SEI CERT Стандарт кодирования Oracle для Java имеет правило MET12-J: не используйте финализаторы. (Обратите внимание, это сайт о безопасном кодировании.) В частности, там говорится
Improper use of finalizers can result in resurrection of garbage-collection-ready objects and result in denial-of-service vulnerabilities.
Oracle Руководство по безопасному кодированию для Java SE более подробно описывает потенциальные проблемы безопасности, которые могут возникнуть при завершении. В этом случае это не проблема с кодом, использующим финализацию. Вместо этого можно использовать финализацию злоумышленником для атаки на чувствительный код, который не защитил себя должным образом. В частности, Руководство 7-3 / ОБЪЕКТ-3 частично утверждает,
Partially initialized instances of a non-final class can be accessed via a finalizer attack. The attacker overrides the protected
finalizemethod in a subclass and attempts to create a new instance of that subclass. This attempt fails ... but the attacker simply ignores any exception and waits for the virtual machine to perform finalization on the partially initialized object. When that occurs the maliciousfinalizemethod implementation is invoked, giving the attacker access tothis, a reference to the object being finalized. Although the object is only partially initialized, the attacker can still invoke methods on it....
Таким образом, наличие механизма финализации в платформе накладывает нагрузку на программистов, пытающихся писать код высокой надежности.
Финализация усложняет спецификации
Платформа Java определяется несколькими спецификациями, включая спецификации языка, виртуальной машины и API библиотеки классов. Влияние финализации тонко распространяется на все это, но оно постоянно дает о себе знать. Например, финализация очень тонко взаимодействует с созданием объекта (что уже достаточно сложно). Завершение также появилось в общедоступных API-интерфейсах Java, а это означает, что эволюция этих API-интерфейсов (до сих пор) требовалась, чтобы оставаться совместимыми с ранее указанным поведением. Развитие этих спецификаций удорожается наличием доработки.
Финализация усложняет реализацию
В основном это касается сборщиков мусора. Существует несколько реализаций сборки мусора, и все они должны оплачивать стоимость реализации финализации. Реализации достаточно хороши для минимизации накладных расходов во время выполнения, если финализация не используется. Тем не менее, реализация все еще должна быть там, и она должна быть правильной и хорошо протестированной. Это постоянное бремя разработки и обслуживания.
Резюме
Мы видели в другом месте, что программистам не рекомендуется использовать финализацию. Однако, если что-то бесполезно, это не обязательно означает, что оно должно быть объявлено устаревшим. Приведенные выше пункты иллюстрируют тот факт, что даже если финализация не используется, простое присутствие механизма в платформе налагает постоянные затраты на спецификацию, разработку и обслуживание. Учитывая бесполезность этого механизма и связанные с ним затраты, имеет смысл отказаться от него. В конце концов, избавление от финализации пойдет на пользу всем.
На момент написания этой статьи (04.06.2019) нет конкретного плана по удалению финализации из Java. Тем не менее, это, безусловно, намерение сделать это. Мы объявили метод Object.finalize устаревшим, но не пометили его для удаления. Это формальная рекомендация программистам прекратить использование этого механизма. Неофициально известно, что финализацию использовать нельзя, но формальный шаг сделать, конечно же, необходимо. Кроме того, некоторые методы finalize в библиотечных классах (например, ZipFile.finalize) объявлены устаревшими «для удаления», что означает, что поведение финализации этих классов может быть удалено из будущего выпуска. В конце концов, мы надеемся отключить финализацию в JVM (возможно, сначала опционально, а затем по умолчанию), и в какой-то момент в будущем действительно удалить реализацию финализации из сборщиков мусора.
(Редактировать 2021-11-03: JEP 421 только что был опубликован, в котором предлагается отказаться от финализации для удаления. На момент написания статьи он находится в состоянии «кандидат», но я ожидаю, что он будет продвигаться вперед. Устаревание, добавленное этим JEP, является официальным уведомлением. эта финализация будет удалена в какой-то момент в последующем выпуске Java. Возможно, неудивительно, что материал в этом ответе и в JEP частично совпадает, хотя JEP более точен и описывает умеренную эволюцию нашего мышления по этой теме. .)
Завершение действительно сложное дело. Так что небольшая поправка: только финализатор, пытающийся воскресить себя, срабатывает только один раз. Но финализатор может воскресить другой инкапсулированный объект, достижимый финализатором, после чего создать новый экземпляр этой оболочки, который может снова воскресить объект, процедура, которую можно выполнять произвольное количество раз. Не то чтобы это был рекомендуемый шаблон…
@ Хольгер Верно. Правило касается вызова метода finalize, а не «воскрешения» как таковой. Я обновил текст, чтобы быть более точным.
@StuartMarks finalization can easily break subclass/superclass relationships Как?
@GovindaSakhare Вкратце, если подклассу по какой-либо причине не удается вызвать super.finalize (), финализация суперкласса не произойдет.
См. также обсуждения, связанные с ошибкой OpenJDK: bugs.openjdk.java.net/browse/JDK-8165641