05JVM-垃圾收集算法

一、垃圾收集算法

1. 标记-清除

  • 标记-清除算法分两个阶段:标记和清除

  • 首先标记出所有需要回收的对象,在标记完成后统一回收。标记的标准就是利用可达性分析算法

这种算法存在一些问题,首先是遍历所有的对象,本身这个效率就存在问题,清除标记的对象后,会存在大量不连续的内存碎片,如果程序运行过程中需要分配大的对象时,无法找到足够多的连续内存时,就会不得不提前触发垃圾回收动作。

2. 复制算法

  • 为解决效率问题,复制的垃圾收集算法出现了。原理是这样的:将内存按容量划分为大小相等的两块,每次只是用一块,当这一块内存用完后,还存活的对象复制到另外一块。

  • HotSpot 新生代就是采用这种算法,分成Eden区和survivor区,survivor又划分为2个区from和to;当新对象分配是先在eden区分配,当一次垃圾回收,eden和survivor中还存活的对象一次性复制到另外一块survivor中。

  • 划分为3块内容,空间使用率和执行效率来看;内存中基本80%~90%的对象都是“朝生夕死”,所以划分3快内存空间足够用于复制存活的对象且节省了空间

复制算法在对象存活率高时就要进行较多的复制操作,效率同样也会变低,更关键的是还会浪费一部分的空间。更何况有极端的情况时,100%对象需要移动,效率就更难保证了

3. 标记-整理

  • 标记清理算法存在内存碎片的问题,要解决内存碎片的问题就需要在当内存对象回收时,将还存活的对象移动到一个区域,这样空闲的内存空间就会连续。

  • 标记-整理算法就是为解决这个问题产生的,经过一轮标记后,所有存活的对象移动一端,然后直接清理掉边界外的内存

4. 总结

HotSpot中,结合复制算法,标记清理,标记整理算法的优点。垃圾收集器使用不同的策略,于是就有了新生代和老年。然后这两个内存区域采用不同的内存回收算法。

  • 新生代采用复制算法
  • 老年代采用标记整理算法

二、收集算法三个要点

GC 在进行垃圾回收过程中,所有的工作线程都会停止。那么工作线程如何确定停止的时刻,也就是工作线程停止的标准是什么

下面3个点明确了工作线程停止的时机:

1. 枚举根节点

可作为GC Roots节点的主要有全局引用(常量或者类变量)和执行上下文(栈帧中的本地变量)。

在分析GC Roots引用链时,要能确保所有对象冻结在某个时间点,这样才能确保对象引用的准确性。否则在分析过程中对象引用关系在不断变化,造成分析引用结果不正确。

要确保正确分析对象引用关系,在枚举根节点时,必须停止所有的工作线程

2. 安全点

安全点的选定是以“是否具有让程序长时间执行的特征”为标识选定

  • 方法调用
  • 循环跳转
  • 异常跳转

等待这些会产生SafePoint,当GC发生时,用户线程跑到这些最近的安全点时会停顿下来。

两种方案停顿:
1. 抢先式中断:GC发生时,把所有的线程中断,如果发现线程中断的地方不在安全点上,会让它回复,继续运行到安全点上
2. 主动式中断:GC发生时,在用户线程写一个标志,各个线程主动轮询这个标志,发现中断标志为真就自己中断挂起。

3. 安全区域

如果程序在sleep或者blocked状态时,线程无法响应JVM的中断请求,用户线程就很难到达安全点。

Safe Region就是用来解决这种情况

安全区域是指在一段代码片段中,引用关系不会发生变化。

当线程执行到Safe Region中的代码时,首先会标识自己已经进入Safe Region,这样当JVM要发起GC时,就不用理会Safe Region状态的线程了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章