Я перечитал множество вопросов о новичке в Java finalize()
и обнаружил, что это немного сбивает с толку, что никто не дал понять, что finalize () - это ненадежный способ очистки ресурсов. Я видел, как кто-то комментирует, что он использует его для очистки соединений, что действительно страшно, поскольку единственный способ приблизиться к гарантии закрытия соединения - это реализовать try (catch) в конце концов.
Я не учился в CS, но я профессионально программирую на Java уже почти десять лет, и я никогда не видел, чтобы кто-нибудь реализовывал finalize()
в производственной системе. Это по-прежнему не означает, что он не имеет смысла или что люди, с которыми я работал, делали это правильно.
Поэтому мой вопрос: какие варианты использования существуют для реализации, finalize()
которые не могут быть обработаны более надежно с помощью другого процесса или синтаксиса в языке?
Пожалуйста, предоставьте конкретные сценарии или ваш опыт, просто повторения учебника по Java или окончательного использования по назначению недостаточно, поскольку цель этого вопроса не в этом.
finalize()
. Однако код библиотеки платформы , напримерSocketInputStream
, который управляет собственными ресурсами от имени вызывающей стороны, делает это, чтобы минимизировать риск утечек ресурсов (или использует эквивалентные механизмы, такие какPhantomReference
, которые были добавлены позже). Таким образом, экосистема нуждается в них хотя 99,9999% разработчиков никогда не напишут.Ответы:
Вы можете использовать его в качестве backstop для объекта, содержащего внешний ресурс (сокет, файл и т. Д.). Реализуйте
close()
метод и документ, который нужно вызвать.Реализуйте,
finalize()
чтобы сделатьclose()
обработку, если вы обнаружите, что это не было сделано. Может быть с чем-то сброшено, чтобыstderr
указать, что вы убираете после глючного звонящего.Это обеспечивает дополнительную безопасность в исключительной / глючной ситуации. Не каждый абонент будет делать правильные
try {} finally {}
вещи каждый раз. К сожалению, но верно в большинстве сред.Я согласен, что это редко нужно. И, как отмечают комментаторы, это идет с накладными расходами GC. Используйте только в том случае, если вам нужна безопасность «ремня и подтяжек» в длительном приложении.
Я вижу, что с Java 9
Object.finalize()
устарела! Они указывают на насjava.lang.ref.Cleaner
и вjava.lang.ref.PhantomReference
качестве альтернативы.источник
finalize()
является подсказкой для JVM, что было бы неплохо выполнить ваш код в неуказанное время. Это хорошо, когда вы хотите, чтобы код загадочным образом не работал.Делать что-либо существенное в финализаторах (в основном все, кроме логирования) также хорошо в трех ситуациях:
Если вы считаете, что вам нужен finalize (), иногда вам действительно нужна фантомная ссылка (которая в приведенном примере может содержать жесткую ссылку на соединение, используемое его референтом, и закрывать его после того, как фантомная ссылка была помещена в очередь). У него также есть свойство, которое он может таинственно никогда не запускать, но, по крайней мере, он не может вызывать методы или воскрешать завершенные объекты. Так что это как раз подходит для ситуаций, когда вам абсолютно не нужно точно закрывать это соединение, но вы бы очень этого хотели, и клиенты вашего класса не могут или не будут звонить близко друг к другу (что на самом деле достаточно справедливо - что' смысл ли вообще иметь сборщик мусора, если вы разрабатываете интерфейсы, которые требуют определенных действий перед сборкой ? Это просто возвращает нас во времена malloc / free.)
В других случаях вам нужен ресурс, который вы считаете более эффективным. Например, почему вам нужно закрыть это соединение? В конечном итоге он должен основываться на каком-либо вводе-выводе, предоставляемом системой (сокет, файл и т. Д.), Так почему же вы не можете полагаться на то, что система закроет его для вас, когда выделен самый низкий уровень ресурсов? Если серверу на другом конце абсолютно необходимо, чтобы вы аккуратно закрыли соединение, а не просто уронили сокет, то что произойдет, если кто-то споткнется о кабель питания машины, на которой работает ваш код, или промежуточная сеть погаснет?
Отказ от ответственности: я работал над реализацией JVM в прошлом. Я ненавижу финализаторы.
источник
finalize()
без объяснения причин, по которым кто-то действительно захочет его использовать.java.lang.ref.Reference
и его подклассы. В Java 1 действительно были переменные :-) И да, у нее тоже были финализаторы.Простое правило: никогда не используйте финализаторы.
Уже одного факта, что объект имеет финализатор (независимо от того, какой код он выполняет), достаточно, чтобы вызвать значительные издержки на сборку мусора.
Из статьи Брайана Гетца:
источник
Единственный раз, когда я использовал finalize в производственном коде, было выполнение проверки того, что ресурсы данного объекта были очищены, и если нет, то записывать очень громкое сообщение. На самом деле он не пытался сделать это сам, он просто много кричал, если это не было сделано должным образом. Оказалось весьма полезным.
источник
Я профессионально занимаюсь Java с 1998 года и никогда не реализовывал
finalize()
. Ни разу.источник
Принятый ответ хорош, я просто хотел добавить, что теперь есть способ завершить работу, не используя ее вообще.
Посмотрите на «Справочные» классы. Слабая ссылка, фантомная ссылка и мягкая ссылка.
Вы можете использовать их, чтобы сохранить ссылку на все ваши объекты, но эта ссылка ALONE не остановит GC. Неплохо то, что вы можете вызывать метод, когда он будет удален, и этот метод может быть гарантированно вызван.
Что касается финализации: я использовал финализацию один раз, чтобы понять, какие объекты были освобождены. Вы можете играть в некоторые аккуратные игры со статикой, подсчетом ссылок и тому подобным - но это было только для анализа, но следите за кодом, подобным этому (не только в финализации, но именно там вы, скорее всего, увидите это):
Это признак того, что кто-то не знал, что делал. Такая «очистка» практически никогда не нужна. Когда класс GC'd, это делается автоматически.
Если вы найдете такой код в финализации, это гарантирует, что человек, который написал его, был сбит с толку.
Если это где-то в другом месте, возможно, код является допустимым исправлением для плохой модели (класс остается в течение долгого времени, и по некоторым причинам вещи, на которые он ссылается, должны были быть вручную освобождены до того, как объект будет собран GC). Обычно это потому, что кто-то забыл удалить слушателя или что-то в этом роде и не может понять, почему их объект не является GC, поэтому они просто удаляют вещи, на которые он ссылается, пожимают плечами и уходят.
Это никогда не должно использоваться, чтобы убрать вещи "Быстрее".
источник
Я не уверен, что вы можете сделать из этого, но ...
Таким образом, я думаю, что Солнце обнаружило несколько случаев, когда (они думают) это следует использовать.
источник
finalize
а не фактически используют ее?$FAVORITE_IDE
.====================================
результат:
=====================================
Таким образом, вы можете сделать недоступный экземпляр доступным в методе finalize.
источник
System.gc();
не является гарантией того, что сборщик мусора действительно будет работать. Это полное усмотрение GC по очистке кучи (может быть, все еще достаточно свободной кучи, может быть, не фрагментированной, ...). Так что это всего лишь скромная просьба программиста: «Пожалуйста, вы могли бы выслушать меня и запустить?» а не команда «беги сейчас, как я говорю!». Извините за использование языковых слов, но это говорит о том, как именно работает GC JVM.finalize()
может быть полезно для обнаружения утечек ресурсов. Если ресурс должен быть закрыт, но это не так, напишите, что он не был закрыт для файла журнала, и закройте его. Таким образом вы устраните утечку ресурсов и дадите себе возможность узнать, что это произошло, чтобы вы могли это исправить.Я программирую на Java с версии 1.0 alpha 3 (1995), и мне еще предстоит переопределить финализировать что-либо ...
источник
Вы не должны зависеть от finalize () для очистки ваших ресурсов. finalize () не будет работать, пока класс не будет собран мусором, если тогда. Гораздо лучше явно освобождать ресурсы, когда вы их используете.
источник
Чтобы выделить точку в ответах выше: финализаторы будут выполняться в одиночном потоке GC. Я слышал о крупной демонстрации Sun, где разработчики добавили небольшой сон некоторым финализаторам и намеренно поставили на колени необычную 3D-демонстрацию.
Лучше всего избегать, с возможным исключением диагностической диагностики.
У Eckel's Thinking in Java есть хороший раздел на эту тему.
источник
Хм, я однажды использовал его для очистки объектов, которые не были возвращены в существующий пул.
Их много раздали, поэтому было невозможно сказать, когда их можно было безопасно вернуть в бассейн. Проблема заключалась в том, что при сборке мусора вводился огромный штраф, который намного превышал любую экономию от объединения объектов. Это было в производстве около месяца, прежде чем я разорвал весь пул, сделал все динамично и покончил с этим.
источник
Будьте осторожны с тем, что вы делаете в
finalize()
. Особенно, если вы используете его для таких вещей, как вызов close () для обеспечения очистки ресурсов. Мы столкнулись с несколькими ситуациями, когда у нас были библиотеки JNI, связанные с работающим java-кодом, и при любых обстоятельствах, когда мы использовали finalize () для вызова методов JNI, мы могли получить очень плохое повреждение кучи Java. Повреждение не было вызвано самим исходным кодом JNI, все следы памяти были в порядке в собственных библиотеках. Это был просто тот факт, что мы вообще вызывали JNI-методы из finalize ().Это было с JDK 1.5, который все еще широко используется.
Мы не узнаем, что что-то пошло не так, пока намного позже, но в итоге виновником всегда был метод finalize (), использующий вызовы JNI.
источник
При написании кода, который будет использоваться другими разработчиками, для освобождения ресурсов требуется некоторый метод «очистки». Иногда эти другие разработчики забывают вызвать ваш метод очистки (или закрыть, или уничтожить, или как угодно). Чтобы избежать возможных утечек ресурсов, вы можете проверить в методе finalize, чтобы убедиться, что метод был вызван, и если это не так, вы можете вызвать его самостоятельно.
Многие драйверы баз данных делают это в своих реализациях Statement и Connection, чтобы обеспечить небольшую безопасность от разработчиков, которые забывают обращаться к ним близко.
источник
Редактировать: Хорошо, это действительно не работает. Я реализовал это и подумал, что если это иногда не удается, это нормально для меня, но он даже не вызывал метод finalize один раз.
Я не профессиональный программист, но в моей программе у меня есть пример, который я считаю примером удачного использования finalize (), то есть кеш, который записывает свое содержимое на диск до его уничтожения. Поскольку нет необходимости, чтобы он выполнялся каждый раз при уничтожении, он только ускоряет мою программу, я надеюсь, что я не сделал это неправильно.
источник
Это может быть удобно, чтобы удалить вещи, которые были добавлены в глобальное / статическое место (по необходимости), и которые должны быть удалены при удалении объекта. Например:
источник
this
экземпляр, переданный ему в конструкторе, этот экземпляр никогда не станет недоступным, следовательно,finalize()
он никогда не очистится в любом случае. Если, с другой стороны, слушатель имеет слабую ссылку на этот объект, как следует из названия, эта конструкция рискует быть очищенной в те моменты, когда этого не следует делать. Жизненные циклы объектов не являются правильным инструментом для реализации семантики приложения.iirc - вы можете использовать метод finalize как средство реализации механизма пулирования для дорогих ресурсов, чтобы они тоже не получали GC.
источник
Как примечание стороны:
Источник: finalize () устарела на Java-9
источник
Ресурсы (File, Socket, Stream и т. Д.) Должны быть закрыты, как только мы закончим с ними. У них обычно есть
close()
метод, который мы обычно вызываем вfinally
разделеtry-catch
операторов. Иногдаfinalize()
могут также использоваться немногие разработчики, но IMO не является подходящим способом, поскольку нет гарантии, что финализация будет вызываться всегда.В Java 7 у нас есть оператор try-with-resources, который можно использовать так:
В приведенном выше примере try-with-resource автоматически закроет ресурс
BufferedReader
, вызвавclose()
метод. Если мы хотим, мы также можем реализовать Closeable в наших собственных классах и использовать его аналогичным образом. ИМО кажется более аккуратным и простым для понимания.источник
Лично я почти никогда не использовал,
finalize()
за исключением одного редкого случая: я создал собственную коллекцию универсального типа и написал собственныйfinalize()
метод, который выполняет следующие действия:(
CompleteObject
Это интерфейс я сделал , что позволяет определить , что вы реализовали редко реализуютсяObject
методы , как#finalize()
,#hashCode()
и#clone()
)Таким образом, используя родственный
#setDestructivelyFinalizes(boolean)
метод, программа, использующая мою коллекцию, может (помочь) гарантировать, что уничтожение ссылки на эту коллекцию также уничтожит ссылки на ее содержимое и удалит любые окна, которые могут непреднамеренно поддержать JVM. Я также подумал о том, чтобы остановить любые темы, но это открыло новую банку с червями.источник
finalize()
на вашихCompleteObject
случаях , как вы делаете в коде выше означает , что она может вызываться дважды, как JVM все еще может вызыватьfinalize()
только эти объекты фактически стали недостижимыми, что, в связи с логикой завершения, может быть , прежде чем вfinalize()
методе вашей специальной коллекции вызывается или даже одновременно в одно и то же время. Поскольку я не вижу каких-либо мер для обеспечения безопасности потоков в вашем методе, вы, похоже, не знаете об этом…Список принятых ответов, что закрытие ресурса во время финализации может быть сделано.
Однако этот ответ показывает, что, по крайней мере, в java8 с JIT-компилятором вы сталкиваетесь с неожиданными проблемами, когда иногда финализатор вызывается даже до того, как вы закончите чтение из потока, поддерживаемого вашим объектом.
Так что даже в такой ситуации не рекомендуется использовать финализацию .
источник