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

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

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

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

5 ответов

Решение

Объект не является мусором. Это известно как "Воскресение объекта".

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

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

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

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

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

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

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

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

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

NB. Как уже отмечали другие... ваш пример определенно стоит избегать.

Другие вопросы по тегам