判断对象是否已死就是找出哪些对象是已经死掉的, 以后不会再用到的, 就像地上有废纸, 饮料瓶和百元大钞, 扫地前要先判断出地上废纸和饮料瓶是垃圾, 百元大钞不是垃圾. 判断对象是否已死有引用计数算法和可达性分析算法.
1. 引用计数算法
给每一个对象添加一个引用计数器, 每当有一个地方引用它时, 计数器值加 1; 每当有一个地方不再引用它时, 计数器值减 1, 这样只要计数器的值不为 0, 就说明还有地方引用它, 它就不是无用的对象. 如下图, 对象 2 有 1 个引用, 它的引用计数器值为 1, 对象 1 有两个地方引用, 它的引用计数器值为 2 .
image
这种方法看起来非常简单, 但目前许多主流的虚拟机都没有选用这种算法来管理内存, 原因就是当某些对象之间互相引用时, 无法判断出这些对象是否已死, 如下图, 对象 1 和对象 2 都没有被堆外的变量引用, 而是被对方互相引用, 这时他们虽然没有用处了, 但是引用计数器的值仍然是 1, 无法判断他们是死对象, 垃圾回收器也就无法回收.
image
2. 可达性分析算法
了解可达性分析算法之前先了解一个概念 --GC Roots, 垃圾收集的起点, 可以作为 GC Roots 的有虚拟机栈中本地变量表中引用的对象, 方法区中静态属性引用的对象, 方法区中常量引用的对象, 本地方法栈中 JNI(Native 方法)引用的对象.
当一个对象到 GC Roots 没有任何引用链相连 (GC Roots 到这个对象不可达) 时, 就说明此对象是不可用的, 是死对象.
如下图: object1,object2,object3,object4 和 GC Roots 之间有可达路径, 这些对象不会被回收, 但 object5,object6,object7 到 GC Roots 之间没有可达路径, 这些对象就被判了死刑.
image
上面被判了死刑的对象 (object5,object6,object7) 并不是必死无疑, 还有挽救的余地. 进行可达性分析后对象和 GC Roots 之间没有引用链相连时, 对象将会被进行一次标记, 接着会判断如果对象没有覆盖 Object 的 finalize() 方法或者 finalize() 方法已经被虚拟机调用过, 那么它们就会被行刑(清除); 如果对象覆盖了 finalize() 方法且还没有被调用, 则会执行 finalize() 方法中的内容, 所以在 finalize() 方法中如果重新与 GC Roots 引用链上的对象关联就可以拯救自己, 但是一般不建议这么做, 周志明老师也建议大家完全可以忘掉这个方法~
3. 方法区回收
上面说的都是对堆内存中对象的判断, 方法区中主要回收的是废弃的常量和无用的类.
判断常量是否废弃可以判断是否有地方引用这个常量, 如果没有引用则为废弃的常量.
判断类是否废弃需要同时满足如下条件:
该类所有的实例已经被回收(堆中不存在任何该类的实例).
加载该类的 ClassLoader 已经被回收.
该类对应的 java.lang.Class 对象在任何地方没有被引用(无法通过反射访问该类的方法).
最后
后续会持续更新 JVM 专题知识及更多架构专题, 写的不好的地方也希望大牛能指点一下, 大家觉得不错可以点个赞在关注下我, 刚刚入驻, 以后还会分享更多文章!
来源: http://www.jianshu.com/p/98409cf47549