怎么肯定对象已经死了?java
怎么肯定对象已经死了?怎么肯定一个对象已经死了?算法
给对象中添加一个引用计数器,每当有个地方引用它,计数器值就加1,引用失效,计数器减1,任什么时候刻计数器为0的对象就不能再应用了。ide
很难解决对象之间的相互循环引用。oop
引用计数收集器能够很快的执行,而且交织在程序运行中,对程序须要不被长时间打断的实时环境比较有利,但其很难解决对象之间相互循环引用的问题。以下面的程序和示意图所示,对象objA和objB之间的引用计数永远不可能为 0,那么这两个对象就永远不能被回收。this
public class ReferenceCountingGC { public Object instance = null; public static void testGC(){ ReferenceCountingGC objA = new ReferenceCountingGC (); ReferenceCountingGC objB = new ReferenceCountingGC (); // 对象之间相互循环引用,对象objA和objB之间的引用计数永远不可能为 0 objB.instance = objA; objA.instance = objB; objA = null; objB = null; System.gc(); }
上述代码最后面两句将objA和objB赋值为null,也就是说objA和objB指向的对象已经不可能再被访问,可是因为它们互相引用对方,致使它们的引用计数器都不为 0,那么垃圾收集器就永远不会回收它们。线程
经过一系列“GC roots”的对象做为起始点,从这些节点开始向下搜索,搜索所走过的路径成为引用链(refenecre chain) ,当一个对象到GcRoot 没有任何的引用链,则证实此对象不可用。3d
Gcroot对象包括:code
虚拟机栈(栈帧中的本地变量表) 中引用的对象。
方法区中类静态属性引用的对象
方法区中常量引用的对象
本地方法栈中JNI(native方法)引用的对象。对象
即时当一个对象不可达到,也并不是非死不可,这时它们处于一个缓行的阶段要真正判处一个对象死亡,至少要经历2次标记。第一次标记为不可达到。当对象没有覆盖finalize() 方法,或者finalize方法已经被虚拟机调用了,虚拟机都被视为不必执行(不必执行是否是直接回收?)blog
若是一个对象被断定有必要执行,则将这个对象放在一个F-Queue的队列中,并由一个线程去执行它。finalize方法是对象逃脱死亡命运的最后机会。当在finalize方法中从新将之间赋值给了某个变量,那么第二次标记就会被移除。若是对象第二次尚未逃脱,那么基本就被回收了。
public class FinalizeEscapeGc { private static FinalizeEscapeGc instance = null; public void alive() { System.out.println("i'm alive"); } /** * 该方法只调用一次 * @throws Throwable */ @Override protected void finalize() throws Throwable { super.finalize(); System.out.println("finalize()"); FinalizeEscapeGc.instance = this; } public static void main(String[] args) throws InterruptedException { instance = new FinalizeEscapeGc(); instance = null; System.gc(); Thread.sleep(500);// finalize() method has a low priority to excute if (instance != null) { instance.alive(); } else { System.out.println("ooops,i'm dead"); } instance = null; System.gc(); Thread.sleep(500); if (instance != null) { instance.alive(); } else { System.out.println("ooops,i'm dead"); } } }
输出:
finalize()
i’m alive
ooops,i’m dead
方法区在hotspot虚拟机称为永久代,永久代的垃圾收集主要回收两部份内容:废弃常量和无用的类。回收废弃常量与回收堆相似,当一个字符串“abc”,进入了常量池,且没有任何String对象叫“abc”,那么它将会被回收。
判断一个类为无用的类:
该类的全部实例都被回收加载该类的classloader已经被回收该类对应java.lang.class对象没有在任何地方引用,没法经过反射访问该类。