常见 GC 算法思想

2016-03-16 22:18:31   最后更新: 2016-03-17 13:33:05   访问数量:1518




上一篇日志中,我们介绍了 java 虚拟机是如何判断是否应该对对象进行垃圾回收的:

java 对象存活判定算法

这篇日志中我们就来看一下具体的算法实现

 

 

 

如图所示,标记-清除算法是垃圾收集算法中最基础的一个,顾名思义,这个算法分为标记和清除两个阶段,在标记阶段,通过对内存区域的遍历,对需要回收的对象进行标记,然后在清除阶段将已经被标记的对象进行清除

在上一篇日志中,我们说过,事实上这个标记过程需要进行两次标记,从而选出没有 finalize 方法或者已经被执行了 finalize 方法的对象

这个算法有两个不足:

  1. 标记和清除两个过程的效率都不够高
  2. 空间中随后会产生出大量不连续的内存碎片

 

 

 

复制算法解决了标记-清除算法的两个不足,他的算法思想是将完整的内存划分为两等份,每次都只使用其中的一份,即整个内存空间的一半

当一份内存空间被用光以后,对这部分内存进行遍历,凡是不能被回收的对象,都完整复制到另一份内存中顺次存储起来,当整片内存复制完成后,将这一半的内存空间全部释放,然后集中使用另一块内存

 

进一步分析表明,新生代中,98%的对象的生命周期非常短暂,因此无需按照 1:1 划分内存,而是划分成一块较大的 Eden 空间和两块较小的 Survivor 空间,每次都使用 Eden 和两块 Survivor 中的一块,当他们的空间被占满以后,一次性的将不能被回收的对象全部复制到另一块空闲的 Survivor 空间中,清理掉刚刚使用的 Eden 和 Survivor 空间,这样可以将浪费的空闲空间降到很低,最初的 HotSpot 正是这么做的

 

 

然而,虽然改进后的策略降低了空间的浪费,可是却又带来了另一个问题,那就是有可能 Eden 与忙 Survivor 中不能被回收的内存空间大于另一块空闲的 Survivor 所能容纳的全部空间,这时,新生代就需要向老年代“借贷”一块内存,以解燃眉之急

 

上面的描述很明显可以得出一个结论,当对象生命周期很短,以至于每次内存回收都只有很少一部分内存不可以被回收时,复制算法是一个十分高效的算法,然而,对于老年代,这个算法就不怎么适用了

对于老年代,更适用于“标记-整理算法”,这个算法与标记-清除算法很像,区别在于在标记清除的同时,还需要让所有存活的对象向内存的一段移动,从而避免了内存碎片的产生

 

这种算法虽然效率较低,但是对于老年代这种非常不频繁的整理来说,整理的效率并不是什么问题

对于这种将内存划分为新生代和老年代,然后在不同的区域内运用不同的算法进行垃圾收集的算法也被称为“分代收集算法”,这在当前商业虚拟机中被广泛采用

 

HotSpot 对于新生代是使用可达性分析算法实现对象存活判定的

在 HotSpot 实现中,使用一组称为 OopMap 的数据结构存储对象内某个偏移对应的是什么数据,当对象加载完成,加载器就会将对象的这些信息存储到 OopMap,这样,在 GC 扫描时可以直接获取到这些信息

然而,由于很多指令都可以令 OopMap 发生变化,因此只有在被称为“安全点”的特定位置,才能够运行 GC,由于 jvm 是多线程模型,就会发生某些线程运行到安全点而另一些没有,如何让所有线程都在安全点上停顿下来,有两种方案可供选择:

  1. 抢先式中断 -- 在 GC 发生时,首先将所有线程全部中断,然后恢复没有运行到安全点的线程,直到他运行到安全点
  2. 主动式中断 -- 在 GC 发生时,对所有线程设置一个标志,每当线程运行到安全点,则检查该标志,如果标志位真,则自己主动中断挂起,这是当前 java 虚拟机的主要实现方式

 

虽然安全点的方法解决了如何进入 GC 的问题,但是对于 sleep 状态、blogcked 状态等线程没有被分给 CPU 的情况下,线程无法响应 jvm 的中断请求运行至安全点再挂起,这种情况就需要“安全区域”来解决

安全区域指的是在相应代码段中,任何时刻开始 GC 都是安全的

每当线程运行到安全区域,线程首先标识自己已经进入安全区域,这样 jvm 发起 GC 时,就不用管这样的线程了

 

欢迎关注微信公众号,以技术为主,涉及历史、人文等多领域的学习与感悟,每周三到七篇推文,只有全部原创,只有干货没有鸡汤

 






读书笔记      技术帖      内存管理      技术分享      内存      memory      java      jvm      java虚拟机      hotspot      gc      垃圾回收      ibm     


京ICP备15018585号