深入理解JAVA虚拟机(五)HotSpot垃圾收集算法实现

在上一章《JAVA每日一学 - 深入理解JAVA虚拟机(四)JVM垃圾收集算法》我们了解到JVM会有多种垃圾收集的算法策略:标记-清除、复制算法、标记-整理算法,目前主流商业虚拟机都采用“分代收集”算法,不同的区域采用不同的算法策略。今天介绍具体的算法实现:

  1. “Stop The World”

    JVM在进行GC垃圾回收时,首先要找出可回收的对象进行标记,在进行对象分析时,需要冻结所有线程,称为“Stop The World”,有两个方案:

    1) 抢先式中断

    ​ GC发生时,直接中断所有的线程,如果线程不在安全点(Safepoint),就恢复线程,让它跑到安全点上再中断。目前虚拟机实现几乎不采用该方式。

    2) 主动式中断

    ​ GC发生时,设置一个标志,各个线程执行时在安全点主动轮询这个标志,如果中断标志为真时就自己中断挂起。

    3)安全区

    ​ 主动式中断,只能保证在程序执行时,在很短的时间内即可进入安全点,但是如果线程是sleep或Blocked状态,这时候线程就无法响应JVM的中断请求。对于这种情况,就需要安全区域(Safe Region)来解决:安全区域是指在一段代码片段中,引用关系不会发生变化,在这个区域的任意地方开始GC都是安全的,当线程执行到Safe Region中的代码时,首先标识自己进入了Safe Region,这样JVM发起GC时,就不用管标识自己为Safe Region状态的线程,当线程要离开Safe Region时,需要检查系统是否已经完成GC,如果没完成则必须等待GC完成才可以离开。

  2. 标记

    在前面章节《JAVA每日一学 - 深入理解JAVA虚拟机(三)详解JVM对象的存活判定算法》中,我们了解到JVM是通过GC Root可达性分析算法判定对象是否可回收的,所以这里,需要枚举所有的GC Root来找出可回收的对象。前面章节我们了解到可做为GC Root的有以下几种:

    1) 虚拟机栈中引用的对象;

    2) 方法区中类静态属性引用的对象;

    3) 方法区中常量引用的对象;

    4) 本地方法栈中JNI引用的对象;

    就是说,JVM需要枚举上面四类GC Root对象,才能找到所有的可回收对象,但实际上,这个是很耗时的,有的应用仅仅方法区(类静态属性、常量等)就有数百兆,如果逐个检查必然很耗时,所有JVM采用了一个做法,就是提前做好日志,存入一组称为OopMap(JRockit里叫做livemap,J9里叫做GC map)的数据结构中。当类加载完时,HotSpot就会把对象内在什么位置,是什么数据类型计算出来,在JIT编译过程中,也会在安全点(Safepoint)记录下栈和寄存器中哪些位置是引用,这样GC在回收时,可以直接得知这些信息。

通过Safepoint和Safe Region,JVM成功的Stop The World了,通过在安全点记录的OopMap结构数据,JVM快速准确地标记了可收回对象,下面就是内存回收了,具体的回收策略,是通过垃圾收集器实现的,JVM发展到现在,出现了多种垃圾收集器,大概有三类:串行、并行、并发,后续介绍…

坚持原创技术分享,您的支持将鼓励我继续创作!
分享