2-3 垃圾收集器与内存分配策略 - 垃圾收集算法实现

HotSpot垃圾收集算法实现

  • 在前两篇文章中,介绍了如何判断对象存活状态和垃圾收集的几种算法,本篇将介绍HotSpot虚拟机的算法实现,以及通过哪些方法使得GC高效运行。

一、枚举根节点

  • 简述:以可达性分析从GcRoots节点查找引用链这个操作为例,GcRoots节点主要分布在全局性的引用(常量和类静态属性)与执行上下文(栈帧中的本地变量表)中,现在某些应用仅仅方法区就有数百兆,如果逐个检查这里的引用,那么必然会浪费很多时间和资源。

  • 上述时间成本对GC效率的影响主要体现在可达性分析的GC停顿上(sun将这件事称为Stop the world),虚拟机在分析引用链的时候要在一个能确保一致性的快照下进行,不允许在分析过程中引用关系还在不停变化的情况发生,这就导致GC执行期间将停止所有java执行线程来对整个全局引用和执行上下文进行类型检查和分析引用关系。

  • 目前主流的虚拟机采用的都是准确式GC,也就是虚拟机有能力判断执行上下文和全局引用中哪些存放的是对象引用,而不需要挨个检查。HotSpot虚拟机是通过一组叫做OopMap的数据结构来达到这个目的的,在类加载完成的时候,HotSpot虚拟机就把对象内什么偏移量上是什么类型的数据计算出来,在jit编译过程中,也会在特定的位置记录下栈和寄存器中哪些位置是引用。这样,GC在扫描时就可以直接得知这些信息了。

二、安全点

  • 简述:在OopMap的协助下,虚拟机可以快速准确的完成GCRoots枚举,能够显著提高GC执行的时间成本,但是另一个问题随之而来,可能导致引用关系变化,或者说OopMap内容变化的指令会非常多,如果为每条指令都分配一个OopMap,那么会大大增加GC的空间成本。

  • 前面提到过,在特定位置记录OopMap,这些特定位置叫做安全点(safepoint),只有当线程执行到Safepoint的时候才可以停下来执行GC。安全点的选定既不能太少(导致GC等待过久),也不能太多(增加GC运行负荷)。所以产生安全点的选定是以“是否具有让程序长时间执行的特性”为标准,“长时间执行”的最明显特征是方法调用、循环跳转、异常跳转等,具有这些功能的指令才会产生Safepoint。

  • 那么接下来,在GC发生时,如何让所有线程(不包括执行JNI的线程)都执行到最近的安全点在停顿下来?这里有两种解决方案可供选择,抢先式中断(Preemptive Suspension)和主动式中断(Voluntary Suspension)。

  • 抢先式中断不需要程序的执行代码主动去配合,GC发生时,首先把所有线程全部暂停,如果发现有线程停止的位置不在安全点上,那么就恢复线程,让其跑到最近的安全点在停顿。现在几乎没有虚拟机采用抢先式中断来响应GC事件。

  • 主动式中断在需要进行GC时不会对线程进行操作,而是设置一个标志位,当创建对象需要分配内存或者线程执行到安全点时,会主动去查询这个标志位,如果中断标志位为真,那么自动暂停并挂起,等待GC完成根节点枚举(或者整个GC过程)。

三、安全区域

  • 简述:使用safepoint似乎已经完美解决了如何进入GC的问题,但实际情况却不一定,safepoint保证了线程在执行时,在不太长的时间内就会遇到可以进入的safepoint,那么在线程不执行,也就是未分配cpu时间时(例如sleep或者blocked状态),jvm不可能去等待线程被重新分配cpu时间并执行到安全点再去中断挂起。这时就需要安全区域(Safe Region)来解决。

  • 安全区域就是指在一段代码片段之中,引用关系不会发生变化。在这段区域内的任何一个地方开始GC都是安全的,也可以称安全区域是升级版的安全点。

  • 在线程执行到safe region中的代码时,线程更改自己的标识为safe region状态。此时jvm发起GC,不用管已经标识为safe region状态的线程,当线程要离开safe region区域时,检查系统是否已经完成了根节点枚举(或者是整个GC过程),如果完成了,那么线程继续向后执行,如果没完成,那线程需要中断挂起,直到收到可以安全离开safe region的信号为止。

  • 疑问:安全区域开头所说的解决线程未分配cpu时间时,线程如何进入GC,但本节直到结束,书中也没提到关于如何解决未分配cpu时间的线程进入GC的问题,怎么能保证未分配cpu时间的线程一定停留在safe region里呢?难道说线程在cpu分配时间即将结束时,将线程跑到safe region中并等待cpu时间结束?如果不需要保证未分配cpu时间的线程一定停留在safe region中,那么safe point升级为safe region的主要原因也不应该是处理未分配cpu时间线程的垃圾回收呀。哪位大神如果清楚原因,望留言不吝赐教!万分感谢!。

感谢阅读:

由于个人水平有限,如果有不对的地方希望各位能够留言指正,谢谢!

参考书籍:

《深入理解java虚拟机》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值