用空间换时间 —— Java虚拟机的算法实现

带着问题阅读

  • 垃圾回收时,需不需要暂停掉除GC线程外的其他线程?
  • 内存那么大,HotSpot如何快速地找到对象?


导语

上一讲介绍了虚拟机是如何利用可达性算法,判断一个对象是否需要回收,而HotSpot在实现这个算法时,必须对算法的执行效率有严格的要求,才能保证虚拟机的高效运行,那么,HotSpot是如何实现的呢?

本文是Effective Java专栏Java虚拟机专题的第五讲,如果你觉得看完之后对你有所帮助,欢迎订阅本专栏,也欢迎您将本专栏分享给你身边的工程师同学。

在学习本节课程之前,建议您了解一下以下知识点:


快速找出GC Roots

可达性分析算法需要先找到GC Roots(什么是GC Roots),而如何在那么大的内存中找到适合当GC Roots的对象呢?如果每次GC都需要遍历全部内存,必然会消耗很多时间。

而要知道,在GC期间,GC线程以外的其他线程必须被冻结(更正,需不需要STW和垃圾收集器的策略有关,why-does-the-jvm-full-gc-need-to-stop-the-world),不可以出现GC过程对象引用关系还在不断发生变化的情况,因此在GC进行时,必须暂停所有的Java执行线程(Sun称之为“Stop The World”)。所以,虚拟机必须尽量的优化GC过程的效率,减少暂停的时间。那么对于GC Roots,HotSpot是如何快速确定的呢?

这时候,准确式GC的作用就体现出来了,它采用一组称为OopMap的数据结构,来保存对象引用的位置,因此在GC时,虚拟机不必在茫茫内存大海中查找引用,只需要拿着OopMap这本字典,就可以快速地查找到所有的引用,并确定GC Roots了(典型的用空间换时间的做法)。



安全点

通过OopMap,HotSpot可以很快完成GC Roots的查找,但是,如果在每一行代码都有可能发生GC,那么也就意味着得为每一行代码的指令都生成OopMap,这样将占用大量的空间。实际上,HotSpot也不会这么做。

HotSpot只在特定的位置记录了OopMap,这些位置就叫做安全点(Safepoint),也就是说,程序并非在任意地方都可以停下了进行GC,只有到达了安全点之后才能进行。安全点一般在这些指令上产生:方法调用、循环跳转、异常跳转等。

当GC发生时,虚拟机会将中断标志设置为true,各个线程在执行时,到达安全点后,就会主动去轮询这个标志,发现中断标志为true时,就主动中断挂起;否则,则继续执行。


安全区域

前面提到的安全点,是在线程正常执行的前提才才有效的,假如线程处于sleep或者blocked状态,就无法走到安全点去中断挂起,而JVM显然不可能等待线程恢复正常,这个时候,就需要安全区域(Safe Region)来解决。

安全区域是指在一段代码片段内,引用关系不会发生变化,在这段区域内,任意地方开始GC都是安全的

当线程进入Safe Region时,首先标识自己已经进入Safe Region,这样,当HotSpot发起GC时,就不需要管这些安全区域内的线程了;当线程要离开Safe Region时,会检查系统是否已经完成了GC(有些垃圾回收器可能只需要检查是否完成了GC Roots查找),如果完成,则线程继续进行,否则就继续等待,直到受到可以安全离开Safe Region的信号。


总结

这一讲介绍了HotSpot在实现可达性分析算法时的算法,讲解了OopMap、安全点和安全区域等概念,通过这两讲的讲解,你已经知道了,垃圾回收是如何发起的,那么发起之后,又是如何回收的呢?这是接下来要讲的内容。


上一节课后思考题的答案

上一讲的问题是——“GC开始后,是否需要暂停除GC线程以外的其他线程?为什么?

答案在本讲中已经提到了,在GC期间,GC线程以外的其他线程必须被冻结,不可以出现GC过程对象引用关系还在不断发生变化的情况,因此在GC进行时,必须暂停所有的Java执行线程(Sun称之为“Stop The World”)

试想一下,假如GC期间其他线程不暂停,那么对于这两行代码:

obj = null;

obj = new Object();

obj.dosomething();

假如在代码执行到第一行时,GC线程进行了标记,将obj标记为需要回收,然而此时其他线程没有暂中断,继续执行第二行代码,执行完之后,GC遍历待回收的对象,将obj回收,接下来要发生的事情想必大家都很熟悉了——NullPointerException.


参考资料

  • 《深入理解Java虚拟机》 周志明


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值