2009-06-16 3 views
15

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

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

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

+4

+1 потому что это хороший вопрос, но я надеюсь, что это было просто интеллектуальное упражнение. ;) –

+0

не волнуйтесь, это было :) –

ответ

11

Объект не является сборкой мусора. Это известно как «воскрешение объекта».

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

6

Подобная ситуация является причиной того, что использование finalize() обычно обескуражено.

+0

Finalize следует использовать только для бесплатных ссылок на неуправляемые ресурсы. GC в конечном итоге позаботится обо всех управляемых ссылках. –

+6

Нет, финализация НЕ должна использоваться для этого, потому что она выполняется произвольно позже или совсем не работает.Неуправляемые ресурсы должны быть явно освобождены в блоке finally. В лучшем случае finalize() может быть добавленным отказоустойчивым. –

+1

... но даже как отказоустойчивый, это очень проблематично. Поскольку он недетерминирован, он превратит воспроизводимую утечку ресурсов в прерывистую утечку ресурсов, которая происходит реже, но ее гораздо труднее воспроизвести. Был там, сделал это :-(. – sleske

1

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

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

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

N.B. Как указывали другие, ваш пример определенно можно избежать.

9

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

0

Поскольку Java - это безопасный язык и платформа, память не освобождается. Также ассоциированные PhantomReference s не будут выставлены в очередь на их ReferenceQueue. VM только когда-нибудь вызовет finalize на объект. В JVM Spec есть диаграмма хорошего состояния.

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

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