Ссылка на объект во время финализации
Что произойдет, если вы сохраните ссылку на текущий объект во время завершения вызова? Например:
class foo {
...
public void finalize() {
bar.REFERENCE = this;
}
}
Является ли объект мусором, или нет? Что происходит, когда вы пытаетесь получить доступ bar.REFERENCE
потом?
5 ответов
Объект не является мусором. Это известно как "Воскресение объекта".
Вы должны быть осторожны с этим, как только финализатор вызывается, gc не будет вызывать его снова, в некоторых средах, таких как.NET, вы можете перерегистрировать финализатор, но я не уверен насчет Java
Если вам абсолютно необходимо воскресить объекты, эта статья JavaWorld предлагает создать свежий экземпляр, а не воскрешать завершенный экземпляр, потому что если завершающийся экземпляр снова становится пригодным для сбора, он будет просто собран (финализатор не будет запущен снова).
Подобные вещи являются причиной, по которой использование finalize()
как правило, не рекомендуется.
Поскольку Java является безопасным языком и платформой, память не освобождается. Также связано PhantomReference
с не будут ставиться в очередь на их ReferenceQueue
s. ВМ будет только звонить 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. Как уже отмечали другие... ваш пример определенно стоит избегать.