java 可达性算法实现_jvm 可达性分析算法是怎么实现的?

在上一篇文章中,我们说到了jvm使用可达性算法来判断对象是否应该回收。可达性算法从特定的对象集合(即GC Roots Set)出发,逐一判断对象是否可达。具体来说,分成两个阶段:首先枚举所有GC Roots 对象,然后进行可达性分析。

上篇文章列举了有哪些 GC Roots Set,可以看到还是包括挺多类型的,具体的对象数目就更多了。如果在GC时先暂停了用户线程再开始逐个枚举GCRoots对象,肯定需要花费很多时间。有什么方法能够快速枚举GCRoots对象呢?jvm采用OopMap这个数据结构来保存GCRoots对象,在GC时直接通过OopMap就可以得到GCRoots对象了。

那么在什么时候保存GCRoots对象到OopMap呢?jvm引入了安全点概念。当线程运行到安全点时,会保存GCRoots对象到OopMap。进行GC时,GC线程会等所有的用户线程都到达最近的安全点后,再开始进行GC回收,因为只有线程到达安全点,才能保证OopMap是最新的,不会出错。

那么怎么让所有的用户线程都到达最近的安全点呢?有两种方法,抢断式中断和主动式中断。抢断式中断是先让所有的用户线程全部暂停,如果发现某个线程没有到达安全点,就让它重新运行一段时间再中断,直到它到达安全点为止。主动式中断是先设置一个标志位,线程运行时不断轮询这个标志位,如果发现标志位为真,就运行到最近的安全点,然后中断挂起。现在几乎所有的jvm都采用主动式中断的方式来中断线程,执行GC操作。

这里面有一种特殊情况,如果某个线程原来就处于睡眠或者阻塞状态怎么办?如果线程原来就处于这种“不运行”的状态,那肯定不能自己主动进行中断了。让GC线程等待“不运行”的线程重新运行,然后再采用主动式中断,从时间上是不可控的。那么还有什么方法吗?jvm引入了安全区的概论。安全区是指在一段代码片段之中,引用关系是不变的。因此,在这个区域中任意地开始垃圾回收都是安全的。当用户线程执行到安全区里面的代码时,会首先标识自己已经进入了安全区域。如果线程要离开安全区时,需要检查是否已经完成了GC。如果完成了,线程可以继续执行,如果没有完成,线程就需要一直等待,直到收到可以离开安全区的信号为止。

通过暂停所有的用户线程,安全点和安全区,jvm保证了在进行GC时,引用关系是不变的,可以获取到最新的OopMap。

获取到最新的OopMap后,可以得到所有GC Roots对象的集合,然后就可以进行可达性分析了。

参考资料:1)深入理解Java虚拟机:JVM高级特性与最佳实践(第3版) 周志明

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值