对象复活时"The finalize method is never invoked more than once by a JVM for any given object."的含义?
Meaning of "The finalize method is never invoked more than once by a JVM for any given object." in case of Object Resurrection?
根据 Java 文档:
对于任何给定的对象,Java 虚拟机永远不会多次调用 finalize 方法。
- 以上的政策能否帮助使一个对象永生?如果我从 finalize() 方法复活一个对象一次,那么该对象是否会永生,因为 JVM 无法对该对象第二次调用 finalize() 方法?
或
- 如果该对象再次符合 GC 条件(假设指向复活对象的另一个引用符合 GC 条件)那么下次 JVM 将删除该对象而不调用该对象的 finalize() 方法?
我已经尝试通过一些示例代码来验证它并假设第二个是正确的,但需要确认我的理解。
根据ernest_k
它是第 2 个。对象将在不调用其 finalize() 方法的情况下被垃圾收集。
添加我的示例代码来完成这个答案,我创建它是为了验证。
import java.util.HashSet;
import java.util.Set;
class Immortal {
// making it public and non-fianl to modify from outside
public static Set<Immortal> immortals = new HashSet<>();
@Override
protected void finalize() throws Throwable {
System.out.println("Running finalize for " + this);
immortals.add(this); // Resurrect the object by creating a new reference
}
}
public class ObjectResurrection {
public static void callGC() {
// call garbage collection
System.gc();
// wait for some time to give chance to run garbage collection thread
try {
Thread.sleep(10 * 1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) {
Immortal immortal1 = new Immortal();
Immortal immortal2 = new Immortal();
// print objects when they are alive.
System.out.println("immortal1 = " + immortal1);
System.out.println("immortal2 = " + immortal2);
// print immortal set
System.out.println("immortal set = " + Immortal.immortals);
// make all objects garbage collectable
immortal1 = null;
immortal2 = null;
callGC();
// now objects will be null
System.out.println("immortal1 = " + immortal1);
System.out.println("immortal2 = " + immortal2);
// but stays in immortal set
System.out.println("immortal set = " + Immortal.immortals);
// remove all objects from immortal set, and make them again eligible for GC
Immortal.immortals.clear();
callGC();
// again print the immortal set
// this time set will be empty, and those 2 objects will be destroyed by Garbage
// Collection,
// but this time they will not call finalize, because it is already called
// you can notice no output from finalize method in the output this time
System.out.println("immortal set = " + Immortal.immortals);
}
}
以上程序的输出(在我的机器上):
immortal1 = effective.java.item7.finalizer6.Immortal@70dea4e
immortal2 = effective.java.item7.finalizer6.Immortal@5c647e05
immortal set = []
Running finalize for effective.java.item7.finalizer6.Immortal@5c647e05
Running finalize for effective.java.item7.finalizer6.Immortal@70dea4e
immortal1 = null
immortal2 = null
immortal set = [effective.java.item7.finalizer6.Immortal@5c647e05, effective.java.item7.finalizer6.Immortal@70dea4e]
immortal set = []
根据 Java 文档:
对于任何给定的对象,Java 虚拟机永远不会多次调用 finalize 方法。
- 以上的政策能否帮助使一个对象永生?如果我从 finalize() 方法复活一个对象一次,那么该对象是否会永生,因为 JVM 无法对该对象第二次调用 finalize() 方法?
或
- 如果该对象再次符合 GC 条件(假设指向复活对象的另一个引用符合 GC 条件)那么下次 JVM 将删除该对象而不调用该对象的 finalize() 方法?
我已经尝试通过一些示例代码来验证它并假设第二个是正确的,但需要确认我的理解。
根据ernest_k 它是第 2 个。对象将在不调用其 finalize() 方法的情况下被垃圾收集。
添加我的示例代码来完成这个答案,我创建它是为了验证。
import java.util.HashSet;
import java.util.Set;
class Immortal {
// making it public and non-fianl to modify from outside
public static Set<Immortal> immortals = new HashSet<>();
@Override
protected void finalize() throws Throwable {
System.out.println("Running finalize for " + this);
immortals.add(this); // Resurrect the object by creating a new reference
}
}
public class ObjectResurrection {
public static void callGC() {
// call garbage collection
System.gc();
// wait for some time to give chance to run garbage collection thread
try {
Thread.sleep(10 * 1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) {
Immortal immortal1 = new Immortal();
Immortal immortal2 = new Immortal();
// print objects when they are alive.
System.out.println("immortal1 = " + immortal1);
System.out.println("immortal2 = " + immortal2);
// print immortal set
System.out.println("immortal set = " + Immortal.immortals);
// make all objects garbage collectable
immortal1 = null;
immortal2 = null;
callGC();
// now objects will be null
System.out.println("immortal1 = " + immortal1);
System.out.println("immortal2 = " + immortal2);
// but stays in immortal set
System.out.println("immortal set = " + Immortal.immortals);
// remove all objects from immortal set, and make them again eligible for GC
Immortal.immortals.clear();
callGC();
// again print the immortal set
// this time set will be empty, and those 2 objects will be destroyed by Garbage
// Collection,
// but this time they will not call finalize, because it is already called
// you can notice no output from finalize method in the output this time
System.out.println("immortal set = " + Immortal.immortals);
}
}
以上程序的输出(在我的机器上):
immortal1 = effective.java.item7.finalizer6.Immortal@70dea4e
immortal2 = effective.java.item7.finalizer6.Immortal@5c647e05
immortal set = []
Running finalize for effective.java.item7.finalizer6.Immortal@5c647e05
Running finalize for effective.java.item7.finalizer6.Immortal@70dea4e
immortal1 = null
immortal2 = null
immortal set = [effective.java.item7.finalizer6.Immortal@5c647e05, effective.java.item7.finalizer6.Immortal@70dea4e]
immortal set = []