在堆中存放着几乎所有的对象实例,垃圾收集器在对堆进行回收前,第一件事就是要确定这些对象之中哪些还活着,哪些对象已经死去. 判断对象是否已经死亡有以下几种算法:
引用计数法算法
- 定义 : 给对象中添加一个引用计数器,当有一个地方引用时,计数器加1,引用失效时,就减1,当对象的引用计数器为0时,对象就是不可再被使用的.
特点 : JAVA虚拟机中很少使用这种算法,主要原因是它很难解决对象之间的循环引用问题
可达性分析算法
- 定义 : 通过一系列的称为 GC Roots 的对象作为起点,从这些节点开始向下搜索,搜索把走过的路径称为引用链,当一个对象到 GC Roots 没有任何引用链相连(就是从GC Roots 到这个对象不可达)时,则证明此对象是不可用的.如下图
上图中的 5,6,7 对象就是不可达的,就是不可用的.
1) 哪些对象可以作为 GC Roots 对象呢? 1 虚拟机栈(栈帧中的本地变量表)中引用的对象 2 方法区中类静态属性引用的对象 3 方法区中常量引用的对象 4 本地方法栈中JNI引用的对象
2) 再谈引用:(从上到下依次减弱) 1 强引用 : 只要强引用还存在,垃圾收集器永远不回收被引用的对象 2 软引用 : 在内存溢出异常之前,回收对象 3 弱引用 : 在下一次 GC 时,无论当前内存是否足够,都会回收被引用的对象 4 虚引用 : 没用,唯一的用处是在对象回收时,会收到一个系统通知
3) 对象的 finalize() 方法作用 生存还是死亡? 即使在可达性分析算法中不可达的对象,也并非是"非死不可"的,这时候它们暂时处于"缓刑"阶段,要真正宣告一个对象死亡,至少要经历2次标记:
1 如果对象在进行可达性分析后发现对象不可达,那它将会被第一次标记并进行一次筛选,筛选的条件是此对象是否有必要执行finalize()方法.当对象没有覆盖finalize()方法,或者finalize()方法已经执行过,虚拟机将这种情况视为没有必要执行
2 如果对象被判定为有必要执行finalize()方法,那么这个对象将会放置在一个叫做F-Queue的队列之中,并在稍后由一个由虚拟机自动建立的,低优先级的Finalizer线程去执行它.这里所谓的招行是指虚拟机会触发这个方法,但并不承诺等待它运行结束,这样做的原因是,如果一个对象在finalize()方法中做耗时的操作,将很可能会导致 F-Queue队列中的其它对象永久处于等待,甚至导致整个内存回收系统线程崩溃, finalize()方法是对象逃脱死亡命运的最后一次机会,稍后GC将对F-Queue中的对象进行第二次标记,如果对象要在finalize()中成功拯救自己,即只要对象重新和引用链上的任何一个对象发生关联即可,即将自己(this关键字)赋值给某个类变量或者对象的成员变量,那么在第二次标记时它将被移出"即将回收"的集合,如果对象这时候还没有逃脱,那么基本上它真的要被回收了 注:尽量不要用finalize()方法,忘了这个方法