обзор
После сбора объекта, который переопределяет finalize (), он добавляется в очередь финализации для очистки после вызова метода finalize () каждого объекта. Что произойдет, если вы воскресите объект?
Когда вызывается финализ?
Метод finalize вызывается однопоточной системной задачей, которая вызывает этот метод для каждого собранного объекта. Примечание: узлы в очереди завершения являются объектами и также имеют методы finalize () условно. Объекты не могут быть очищены до GC после того, как они были завершены.
Большинство объектов (включая узел в очереди финализации) не переопределяют finalize (), поэтому GC достаточно умен, чтобы обнаружить это и не добавлять их в очередь. Эти объекты могут быть немедленно очищены. Если вы переопределите метод, даже с пустым, он будет иметь значение.
А как насчет воскресших объектов?
В методе finalize () вы можете воскресить объект, указав ему что-то. например, статическая коллекция. Этот объект больше не может быть собран GC (пока он снова не будет удален). Так что же тогда происходит?
Объект был помечен как завершенный один раз и не завершен повторно.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
static final List ZOMBIES = new ArrayList<>(); static class Zombies { private int num; public Zombies( int num) { this .num = num; } @Override protected void finalize() throws Throwable { System.out.println( "Resurrect " + num); ZOMBIES.add( this ); } @Override public String toString() { return "Zombies{" + "num=" + num + '}' ; } } public static void main(String... args) throws InterruptedException { for ( int i = 0 ; i < 3 ; i++) ZOMBIES.add( new Zombies(i)); for ( int j = 0 ; j < 5 ; j++) { System.out.println( "Zombies: " + ZOMBIES); ZOMBIES.clear(); System.gc(); Thread.sleep( 100 ); } } |
печать
1
2
3
4
5
6
7
8
|
Zombies: [Zombies{num= 0 }, Zombies{num= 1 }, Zombies{num= 2 }] Resurrect 2 Resurrect 1 Resurrect 0 Zombies: [Zombies{num= 2 }, Zombies{num= 1 }, Zombies{num= 0 }] Zombies: [] Zombies: [] Zombies: [] |
В этом примере зомби добавляются в коллекцию один раз и воскресают один раз методом финализации. Когда они собраны во второй раз, они помечаются как завершенные и больше не ставятся в очередь.
Вывод
Хотя хорошей идеей является избегать использования finalize (), немного приятно знать, что она будет вызываться только после воскрешения объекта.
Справка: воскресение Java-объекта от нашего партнера по JCG Питера Лоури из блога Vanilla Java .