概述
之前说过,程序计数器,虚拟机栈,本地方法栈是随着线程的产生而产生,随线程的销毁而被销毁。因此垃圾回收主要就是针对Java堆中的内存。一个接口中的多个实现类所需要的内存不一样,一个方法中的多个分支需要的内存也不一样,只有在程序创建过程中才能知道实际的内存要创建多少。
引用计数法
那么怎么确定在回收这些对象的时候确定这些方法是否还活着呢,正常来讲会想到,可能是引用计数法。这种方法会给每个对象创建一个引用计数器,每当一个地方引用到他时,计数器的值就会+1;当引用失效的时候,计数器的值就会-1.当计数器的值为0的时候对象就不可能在被使用了。但是假如说两个对象相互引用呢。难道永远都不回收这些对象吗?
可达性分析算法
先记录一下我画的图,因为在老家电脑不太好使,就使用手绘吧。
这种使用的是树的结构,从GCRoot的对象为起始点,向下搜索,找到其他相关联的对象,例如从虚拟机栈中的引用对象向他所引用的对象进行查找。对于另外的虽然也有引用,但是会将他们放入到被GC的队列当中准备回收。
回收时
当一个对象进入垃圾回收队列也是有可能”起死回生“的,假如对象在调用finalize方法时,引用了上面所提到的可达性链上的对象时,将会被重新使用。例如下面代码
public class TestXu {
public static TestXu SAVE_HOKE = null;
void isAlive(){
System.out.println("我还活着");
}
@Override
protected void finalize() throws Throwable {
super.finalize();
System.out.println("finalize 方法被调用");
SAVE_HOKE =this;
}
public static void main(String[] args) throws InterruptedException {
SAVE_HOKE =new TestXu();
SAVE_HOKE =null;
System.gc();
Thread.sleep(500);
Optional.ofNullable(SAVE_HOKE).ifPresent(TestXu::isAlive);
SAVE_HOKE =null;
System.gc();
Thread.sleep(500);
Optional.ofNullable(SAVE_HOKE).ifPresent(TestXu::isAlive);
}
}
结果
尽管已经是将要被回收的对象,但是他在 finalize()方法中调用了自己,因此他将重新可以被使用。但是由于 finalize()方法只能被一个对象调用一次,因此他在下一次执行时将会被gc。这种方法书上说并不推荐,因为会带来很多的不确定性。