Как finalize () работает в Java? - PullRequest
5 голосов
/ 04 марта 2012

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

В сети я нашел эту схему, иллюстрирующую процесс сборки мусора, и завершил:

This describes the order of operations involving finalize and the JGC:

Пара вопросов:

  1. Это происходит в отдельной теме, верно?
  2. Что произойдет, если я создам новый объект во время финализации? Это разрешено?
  3. Что произойдет, если я вызову статический метод из finalize?
  4. Что произойдет, если я установлю новую ссылку на объект изнутри finalize?

Полагаю, мне следует объяснить, почему я заинтересован. Я много работаю с LWJGL, и кажется, что если бы я мог использовать finalize, чтобы заставить объекты Java автоматически очищать ресурсы OpenGL, то я мог бы сделать некоторые действительно хорошие вещи с точки зрения API.

Ответы [ 3 ]

5 голосов
/ 04 марта 2012

finalize () вызывается сборщиком мусора Java, когда он обнаруживает, что никаких ссылок на этот конкретный объект не существует. finalize () наследуется всеми объектами Java через класс Object.

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

Вы не должны полагаться на finalize () для прояснения, и лучше проясниться, как вы идете. Я предпочитаю использовать try, catch, finally для прояснения, а не finalize (). В частности, используя finalize (), вы заставите JVM удерживать все другие объекты, на которые ссылается ваш финализируемый объект, на случай, если он вызовет их. Это означает, что вы держите память, которую вам не нужно использовать. Что еще более важно, это также означает, что вы можете заставить JVM никогда не в конечном итоге избавляться от объектов, потому что они должны держаться за них, в то время как другой метод завершения объектов нуждается в этом, например. состояние гонки.

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

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

3 голосов
/ 04 марта 2012

Я не думаю, что есть какие-либо гарантии относительно того, какая нить будет использоваться.Могут быть созданы новые объекты и могут быть вызваны статические методы.Установление новой ссылки на ваш объект предотвратит сбор мусора, но метод finalize будет не вызываться снова - вы не хотите этого делать.

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

Метод не гарантированно вызывается. Если вы связали ресурсы, которые не будут автоматически освобождены при остановке вашей программы не зависят от finalize.

Когда вызванный метод не гарантируется,С плотной памятью это будет раньше.С большим количеством свободной памяти, это будет позже, если вообще.Это может вам подойти: с большим объемом памяти вы можете не беспокоиться об освобождении ресурсов.(Хотя их удержание может помешать работе другого программного обеспечения в то же время, и в этом случае вы будете обеспокоены.)

Мое обычное решение - иметь какое-то утилизируйте метод , который выполняет очистку.Я называю это явно в какой-то момент, если смогу, и как только смогу.Затем я добавляю метод finalize, который просто вызывает метод dispose .(Обратите внимание, что метод dispose должен вести себя хорошо при вызове более одного раза! Действительно, при таком типе программирования я мог бы вызывать dispose несколько раз за пределами finalize, не будучи уверенным в том, что предыдущие вызовы были сделаны успешно, и, тем не менее, желая, чтобы он вызывался эффективно как можно скорее.) Теперь, в идеале, мои ресурсы освобождаются, как только они мне больше не нужны.Однако, если я потеряю объект с ресурсами, метод finalize выручит меня, когда памяти не хватит, и мне понадобится помощь.

1 голос
/ 04 марта 2012

Прежде всего, помните, что нет никакой гарантии, что финализация будет выполнена вообще для всех ваших объектов. Вы можете использовать его для освобождения памяти, выделенной в собственном коде, связанном с объектом, но для чистого Java-кода большинство сценариев использования только для выполнения «резервного» механизма очистки ресурсов. Это означает, что в большинстве случаев вы должны освобождать ресурсы вручную, и финализаторы могут действовать только как своего рода помощник для очистки, если вы забудете сделать это стандартным способом. Тем не менее, вы не можете использовать их в качестве единственного или основного механизма очистки. Более того, вы не должны писать код, правильность которого зависит от запуска финализаторов.

Объявление 1. Насколько я знаю, нет никаких гарантий относительно того, что поток вызывает finalize(), хотя на практике это, вероятно, будет один из потоков GC.

Объявление 2. Разрешается создание новых объектов. Тем не менее, есть ряд ловушек с обработкой ссылок на объекты в финализаторах. В частности, если вы храните жесткую ссылку на финализируемый объект в каком-то живом объекте, вы можете предотвратить очистку объекта, собираемого для сбора мусора. Этот вид воскрешения объекта может привести к истощению ваших ресурсов, если он выйдет из-под контроля. Кроме того, следите за исключениями в finalize() - они могут остановить финализацию, но у вашей программы нет автоматического способа узнать о них. Вам нужно обернуть код в блоки try-catch и распространять информацию самостоятельно. Кроме того, длительное время выполнения финализаторов может привести к наращиванию очереди объектов и потреблению большого количества памяти. Некоторые другие примечательные проблемы и ограничения описаны в этой статье JavaWorld .

Объявление 3. Не должно быть проблем с вызовом статических методов из финализаторов.

Объявление 4. Как уже упоминалось в пункте 2, можно предотвратить сбор мусора (воскресить его), поместив ссылку на него в другой живой объект во время финализации. Однако это непростое поведение и, вероятно, не очень хорошая практика.

Подводя итог, вы не можете полагаться на финализаторы для очистки ваших ресурсов. Вы должны справиться с этим вручную, и финализаторы в вашем случае могут в лучшем случае использоваться в качестве механизма резервного копирования, чтобы в некоторой степени скрыть после небрежного кодирования. К сожалению, это означает, что ваша идея сделать API лучше с помощью финализаторов для очистки ресурсов OpenGL, вероятно, не сработает.

...