1.在GC回收对象时需判定对象是否已死,一般判定对象已死有以下2个方法:
1.1引用计数算法一个对象实例每被引用一次计数器就+1,引用失效计数器就-1,当计数器为0时就代表此对象实例没有被引用,即可GC。不过JAVA并不适合这种方法,因为解决不了对象相互循环引用的问题。
PS:这里objA引用这objB,objB引用着objA,但这2个对象的引用都已经为null,在引用计数器的角度来说计数各=1所以不会被回收,而实际在JAVA中是被回收的。
1.2.跟搜索算法2.JAVA里GC至少是标记2次才回收,第一次标记只是告诉JVM此对象可以被回收,然后JVM有个低优先级的队列来处理,在进行第二次标记时如果对象没有被重新关联引用就会真正的被回收掉。起节点是GC Root,然后往下搜索形成引用链,不可达对象即可回收。直接看图比较直观。
一般可以再finalize()方法里重新关联,这个方法只会在GC时触发一次,当对象没有覆盖此方法或此方法已经被调用过就不会再执行finalize(),会直接GC。
下面写个实例:
public class Test {
private static Test instance = null;
@Override
protected void finalize() throws Throwable {
System.out.println("sos~~");
super.finalize();
instance = this;
}
public void alive() {
System.out.println("i am alive");
}
public static void main(String[] args) throws InterruptedException {
instance = new Test();
instance = null;
//GC~会调finalize()方法
System.gc();
//JVM会起一个低优先级的回收队列线程,所以这里睡10秒让回收线程优先执行保证GC。
Thread.sleep(10 * 1000);
if (instance != null) {
instance.alive();
} else {
System.out.println("i am dead");
}
instance = null;
//GC~finalize()已经被调过1次不会再被调用,直接GC。。。
System.gc();
Thread.sleep(10 * 1000);
if (instance != null) {
instance.alive();
} else {
System.out.println("i am dead");
}
}
}
|