Есть ли необходимость в методе финализации Java?

Все, что я читал о методе java finalize, говорит НЕ его использовать. Кажется, что почти никогда не гарантируется, что он будет вызван, и даже если это так, могут возникнуть проблемы.

Есть несколько других вопросов, которые задают, когда его использовать, и, кажется, общее мнение таково: НИКОГДА.

Я никогда не использовал его сам (в основном из-за предупреждений не делать этого) и нигде не видел, чтобы он использовался.

Есть ли вообще случаи, когда это было бы уместно? Бывают ли случаи, когда альтернативы нет?

Если нет, то почему он там? Существуют ли внутренние классы, которые используют его и требуют, чтобы метод был доступен? Или это просто то, чего не должно быть?

Меня не столько интересует, когда я должен его использовать (на что был дан ответ «никогда»), сколько разъяснение того, почему он даже там дан этот ответ «никогда». Если он такой бесполезный и опасный, то почему его не обесценили и не убрали?


person Matthew    schedule 27.02.2016    source источник
comment
@Alex Мой вопрос похож, но я не думаю, что он точно такой же. Я не столько спрашиваю, почему я буду его использовать (мне не следует), сколько, в первую очередь, почему он здесь (учитывая, что я не должен). Требуются ли API-интерфейсы Java по какой-либо причине? Должна ли JVM по какой-то причине видеть этот метод для всех объектов? Или бывают случаи, когда другой альтернативы просто нет? (Третий из них касается вопроса, который вы связали, но первые два - нет).   -  person Matthew    schedule 27.02.2016
comment
@Alex Алекс, я отредактировал свой заголовок, чтобы сделать это различие немного яснее.   -  person Matthew    schedule 27.02.2016
comment
Итак, JLS требует, чтобы он был там, но единственная указанная причина заключается в том, что финализаторы дают возможность освободить ресурсы, которые не могут быть освобождены автоматически с помощью автоматического диспетчера хранилища. В таких ситуациях простое восстановление памяти, используемой объектом, не гарантирует, что ресурсы, которые он содержал, будут восстановлены. В javadoc finalize также говорится, однако обычная цель finalize состоит в выполнении действий по очистке. до того, как объект будет безвозвратно отброшен. Я не знаю другой причины, по которой он был создан.   -  person Alex - GlassEditor.com    schedule 27.02.2016


Ответы (2)


Обратная совместимость. Кто-то сначала подумал, что это будет хорошая идея, а потом, когда мир понял, что это не такая уж хорошая идея, было слишком поздно.

Эти вещи почти никогда не удаляются. В Java полно концепций, которые в настоящее время считаются плохой идеей, но тем не менее не были удалены. Еще несколько примеров, которые приходят мне на ум: clone()< /a> или Thread.stop().

person Jiri Tousek    schedule 27.02.2016
comment
Был ли момент, когда его рекомендовали, или более ранние сборщики мусора работали с ним более надежно? Вроде не должно было зацепиться за выдачу проблем. А если не прижилось, то, кажется, безопаснее его удалить. Я знаю, что java любит обесценивать вещи и при этом не удалять их. Есть ли причина, по которой он хотя бы не обесценился? - person Matthew; 27.02.2016
comment
Я не думаю, что раньше они были более надежными. Некоторые опасности стали известны со временем, когда люди пытались его использовать. Некоторая ненадежность может возникать из-за того, что сегодня JAva GCing реже (из-за большего объема памяти и стратегии максимально возможной задержки GC). - person Jiri Tousek; 27.02.2016
comment
Насколько я понимаю, finally() в основном позволяет освобождать ресурсы, которые не находятся под контролем GC и чье освобождение не является критическим (т.е. если JVM закрыт, они будут освобождены автоматически) - например, выделение памяти через некоторый собственный код при работе с компонентами, отличными от Java, DLL и т. д. - person Jiri Tousek; 27.02.2016
comment
Хорошо, этот комментарий полезен. Это похоже на то, что ответил @MartinS, но различие между некритическими и бесплатными ресурсами кажется лучшим использованием. Использование его для избавления от ресурса, память которого я хочу вернуть, но не собираюсь оставлять систему в каком-то ужасном состоянии, если JVM отключится, кажется более безопасным его использованием. - person Matthew; 27.02.2016
comment
@Matthew Пример, который я упоминаю, также будет считаться некритическими ресурсами в этом отношении. Несмотря на то, что JVM не контролирует память, она все равно будет освобождена операционной системой, если JVM выключится. Просто вы не хотите утечки памяти в долго работающих программах :) - person MartinS; 27.02.2016

Один из вариантов использования, где вы можете его использовать и где это было бы приемлемо, — это освобождение ресурсов, которые не находятся под контролем JVM, т. е. которые иначе не были бы освобождены. Например, память, выделенная с помощью sun.misc.Unsafe(*), должна быть освобождена вручную, потому что она не будет удалена сборщиком мусора. Таким образом, вы можете использовать метод finalize в качестве последнего средства для освобождения памяти, если она не была освобождена ранее - просто чтобы убедиться, что в вашей программе нет утечек памяти. Но такие случаи довольно редки, и сегодня Java предоставляет лучшие альтернативы, такие как интерфейс AutoClosable, представленный в Java 7.

Вы можете найти больше примеров в исходном коде OpenJDK, например FileInputStream, который использует метод finalize, чтобы убедиться, что он закрыт.

(*) Не используйте его, он называется Unsafe не просто так.

Изменить: ответы на вопросы из вашего комментария.

Требуется ли это по какой-либо причине для API Java?

И да и нет. В спецификации языка Java говорится что он должен существовать. Также некоторые классы в библиотеке Java используют его (например, когда они обрабатывают файлы), но ни один API Java не требует, чтобы вы реализовали его для своих классов.

Должна ли JVM по какой-то причине видеть этот метод для всех объектов?

Да, опять же, потому что так говорит JLS, и сборщик мусора вызывает его для каждого объекта, который он собирает.

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

Но он видит метод finalize для всех объектов, начиная с Object реализует его — и ничего не делает по умолчанию.

protected void finalize() throws Throwable { }
person MartinS    schedule 27.02.2016
comment
Я понимаю, почему в этом случае вы бы рассмотрели это, но, учитывая, что нет гарантии, что он будет работать, будет ли это то, на что вы хотите положиться, чтобы освободить эти ресурсы? На самом деле я ничего подобного не делал, но кажется, что все еще есть хороший шанс, что эти ресурсы не будут правильно освобождены, учитывая непредсказуемость. - person Matthew; 27.02.2016
comment
Вот почему я сказал в крайнем случае. Это все же лучше, чем ничего не делать, когда программист забыл где-то освободить ресурс, потому что у вас, по крайней мере, будет хороший шанс, что finalize в конце концов будет вызван. - person MartinS; 27.02.2016