垃圾回收的可触及性

Posted 点滴

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了垃圾回收的可触及性相关的知识,希望对你有一定的参考价值。

可触及性的3种状态:
1.可触及的:从根节点开始,可以到达这个对象。
2.可复活的:对象的所有引用都被释放,但是对象有可能在finalize()函数中复活。
3.不可触及的:对象的finalize()函数被调用,并且没有复活,那么就会进入不可触及状态,不可触及的对象不能被复活,因为finalize()函数只会被调用一次。

对象的复活
/**
* Created by xxd on 2017/4/4.
*/
public class CanReliveObj {
public static CanReliveObj obj;

@Override
protected void finalize() throws Throwable{
super.finalize();
System.out.println("CanReliveObj finalize called");
obj = this;
}

@Override
public String toString(){
return "I am CanReliveObj";
}

public static void main(String[] args) throws InterruptedException{
obj = new CanReliveObj();
obj = null;
System.gc();
Thread.sleep(1000);
if (obj == null){
System.out.println("obj is null");
}else{
System.out.println("obj is useful");
}
System.out.println("the second gc");
obj = null;
System.gc();
Thread.sleep(1000);
if (obj == null){
System.out.println("obj is null");
}else{
System.out.println("obj is useful");
}
}
}
运行结果如下
第一次将obj设置为null后,进行GC,结果obj对象被复活。
第二次将obj设置为null,并GC后,对象才被真正的回收。

这是因为在第一次GC时,在finalize()函数调用之前,虽然系统中的引用已经被清除,但是作为实例方法finalize(),对象的this引用依然会被传入方法内部,如果引用外泄,对象就会复活。

此时,对象又变为可触及状态。

而finalize()函数只会被调用一次,因此,在第二次清除对象时,对象就无机会复活,因此就会被回收。

注意:
1.finalize()函数有可能发生引用外泄,在无意中复活对象;
2.由于finalize()是被系统调用的,调用时间是不明确的,因此不是一个好的资源释放方案,推荐在try-catch-finally语句中进行资源的释放。

以上是关于垃圾回收的可触及性的主要内容,如果未能解决你的问题,请参考以下文章

java 垃圾收集

深入JVM垃圾回收

深入JVM垃圾回收

JVM的GC理论详解

如何从片段到活动而不会干扰片段的可重用性

对“xxx”类型的已垃圾回收委托进行了回调。这可能会导致应用程序崩溃损坏和数据丢失。向非托管代码传递委托时,托管应用程序必须让这些委托保持活动状态,直到确信不会再次调用它们。 错误解决一例。(代码片段