Ссылка на объект во время завершения

Что произойдет, если вы сохраните ссылку на текущий объект во время вызова finalize? Например:

class foo {
    ...
    public void finalize() {
        bar.REFERENCE = this;
    }
}

Является ли объект сборщиком мусора или нет? Что произойдет, если вы попытаетесь получить доступ к bar.REFERENCE позже?


person Nathaniel Flath    schedule 16.06.2009    source источник
comment
+1, потому что это хороший вопрос, но я надеюсь, что это было просто интеллектуальное упражнение. ;)   -  person Michael Myers    schedule 16.06.2009


Ответы (5)


Объект не подвергается сборке мусора. Это известно как «Воскресение объекта».

Вы должны быть осторожны с этим, как только финализатор вызывается, gc не будет вызывать его снова, в некоторых средах, таких как .NET, вы можете перерегистрировать финализатор, но я не уверен насчет java

person albertein    schedule 16.06.2009

Если вам абсолютно необходимо воскресить объекты, этот JavaWorld В статье предлагается создать новый экземпляр, а не воскрешать финализируемый экземпляр, потому что, если финализируемый экземпляр снова станет пригодным для сбора, он будет просто собран (финализатор не будет запускаться снова).

person Aaron Maenpaa    schedule 16.06.2009

Такого рода вещи являются причиной того, что использование finalize() обычно не рекомендуется.

person Michael Borgwardt    schedule 16.06.2009
comment
Finalize следует использовать только для освобождения ссылок на неуправляемые ресурсы. В конечном итоге GC позаботится обо всех управляемых ссылках за вас. - person Ryan Michela; 16.06.2009
comment
Нет, finalize НЕ следует использовать для этого, потому что он запускается в произвольный более поздний момент времени или вообще не запускается. Неуправляемые ресурсы должны освобождаться явно в блоке finally. В лучшем случае finalize() может стать дополнительной защитой от сбоев. - person Michael Borgwardt; 16.06.2009
comment
... но даже в качестве отказоустойчивого это очень проблематично. Поскольку он недетерминирован, он превратит воспроизводимую утечку ресурсов в прерывистую утечку ресурсов, которая случается реже, но ее гораздо сложнее воспроизвести. Был там, сделал это :-(. - person sleske; 04.10.2010
comment
@Michael Borgwardt, не могли бы вы поделиться какими-нибудь хорошими материалами о финализации? - person gstackoverflow; 21.10.2018

Метод finalize() может быть вызван явно для экземпляра foo, или он может быть вызван сборщиком мусора, когда он пытается освободить память, занятую этим объектом.

Если bar является допустимым экземпляром, он устанавливает в поле REFERENCE экземпляр foo. С точки зрения сборщика мусора это увеличивает счетчик ссылок foo.

Если внутри метода finalize() возникает исключение (например, NullPointerException из-за того, что bar является null), то процесс финализации просто завершается.

Н.Б. Как указывали другие ... вашего примера определенно следует избегать.

person octy    schedule 16.06.2009

Поскольку Java — безопасный язык и платформа, память не освобождается. Также связанные PhantomReferences не будут поставлены в очередь на их ReferenceQueues. Виртуальная машина будет вызывать finalize для объекта только один раз. В спецификации JVM есть хорошая диаграмма состояний.

Обычно, если вы используете финализатор, вы должны оставить объявление как @Override protected void finalize() throws Throwable, чтобы не мешать работе API. Еще лучше использовать защищенный финализатор, как в Effective Java 1st Ed.

Этот конкретный трюк попал в заголовки (во всяком случае, о Сан-Хосе Меркьюри), когда группа в Принстоне использовала его для создания собственного ClassLoader из ненадежного кода. Несмотря на то, что спецификация была немного ужесточена (конструктор Object должен завершить нормальное выполнение, прежде чем можно будет вызвать финализатор - указано в J2SE 5.0, реализовано в Java SE 6), это все еще остается проблемной областью. Если вы разрабатываете API, убедитесь, что чувствительные классы не могут быть подклассами, и избавьте себя от хлопот.

person Tom Hawtin - tackline    schedule 16.06.2009