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

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

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

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

Ответы

Ответ 1

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

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

Ответ 2

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

Ответ 3

Это то, почему использование finalize() обычно обескуражено.

Ответ 4

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

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

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

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

Ответ 5

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

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

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