JVM学习(2)-JVM垃圾回收算法

java虚拟回收垃圾对象时,一份分为两步:
1、虚拟机在回收堆空间在之间,会先判断哪些对象已经死亡;
2、然后再对这些死亡对象通过特定的回收算法进行回收
 
一、判断对象是否死亡
1、引用计算器算法
给对象添加一个引用计算器,如果其他地方引用它,计算器就加1,当引用失效时,计算器就减1。当计算器为0时,这个对象不能被再次使用,需要被回收了。
优点:实现简单
缺点:不能解决对象之间相互循环引用的问题。
 
2、根搜索算法GC Roots Tracing
通过一系列的名为GC Roots作为对象为起始点,从这些节点开始向下搜索,搜索走过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连,也就是不可达(图论中迪杰斯特拉算法),证明此对象是不可用的。
在java语言里,可作为GC Roots的对象包括以下几种:
  • 虚拟机栈(栈帧中的本地变量表)中引用的对象
  • 方法区中的类静态属性引用的对象
  • 方法区中的常量引用的对象
  • 本地方法栈中JNI(即一般说的Native方法)的引用的对象
ps:会进行二次判断,在判断对象为死亡对象后,虚拟机会吧对象放到F-QUEUE队列里,然后启动一个线程去扫描,如果发现扫描后依然没有被引用,那么就直接回收了。
 
 
二、垃圾回收算法
1、标记-清除算法
分为标记和清除两个阶段,首先标记处需要清除的对象,标记完成之后统一回收掉所有被标记的对象。
缺点:效率低,造成碎片比较多
 
2、复制算法
把可用内存分为相等的两份,每次只是用一块。当这一块内存用完了,就把所有的存活的对象都复制到另外一份内存块中,然后一次性全部把这块内存清除掉。
现在很多虚拟机就是采用这种方式回收新生代。新生代分为一块大的Eden空间,和两块小的Survivor空间,每次使用Eden和其中的一块Survivor。当回收时,把Eden和Survivor还存活的对象一次性全部拷贝到另外一块Survivor空间上,最后清理掉Eden和刚才使用的Survivor空间。如果Survivor空间不够时,会向老年代进行借一部分内存。
优点:简单高效,碎片率也比较低。
 
3、标记-整理算法
如果存活率比较高,那么使用复制算法就不适用。
把所有的存活对象都往前端转移,然后直接清理掉端边界以外的内容。 
针对老年代使用。
 
4、分代收集算法
现在的虚拟机一般都是采用这种方式。
把java堆分为新生代和老年代,新生代则采用复制算法,老年代则采用标记-整理算法。