深入JVM HotSpot算法实现

关于GC回收,主要设计对象存活判定算法和垃圾回收算法,而在经典的HotSpot虚拟机实现这些算法时,必须对算法实现细节进行严格约束,才能保证虚拟机高效执行。

——枚举根节点

从可达性分析中从GC Roots节点找引用链操作为例,可作为GC Roots节点主要在全局性的引用上(如常量或类的静态属性)与执行上下文(如栈帧中的本地变量表)。但是较大的引用程序仅仅方法区就数以百兆,如果逐个检查这些引用,必然消耗大量时间

另外,可达性分析对执行时间敏感还体现在GC停顿上,因为此项分析工作必须在确保一致性的快照中进行(一致性 指的是整个分析期间整个执行系统处于一个冻结状态),不能出现分析过程对象引用关系还在不断变化的情况,否则分析结果无法确保准确性。这导致GC进行时必须停顿所有Java执行线程

当执行系统短暂停顿时,并不需要一个不漏的检查执行上下文和全局引用,虚拟机应当有办法直接得知哪些地方存放对象引用,在HotSpot虚拟机实现中,使用一组OopMap的数据结构来达到这个目的,在类加载过程中,HotSpot把对象偏移量上的数据类型分析出,而在JIT编译中,也会在特定位置记录下栈中什么位置存放对象引用。这样GC扫描时便得知这些信息。

——安全点

在OopMap协助下,HotSpot可以快速且准确的完成GC Roots枚举工作,但会发生一个问题:可能导致引用关系变化,即引起OopMap内容变化的指令很多,如果为每一条指令生成对应的OopMap 将需要大量的额外空间,GC的空间成本也提高

实际上,HotSpot没有为每条指令生成OopMap 只是在特定位置记录了这些信息,这些位置称为“安全点” 即程序执行时并非在所有地方都停顿下来开始GC 只有到达安全点时才能停顿。SafePoint的选定既不能太少以至于让GC等待时间太长,也不能过于频繁以致于过分增大运行时的负荷。所以 安全点的选定基本以程序 是否具有让程序长时间执行的特征 为标准选定的——因为每条指令执行的时间非常短,程序不太可能因为指令流长度太长而过长时间运行,“长时间执行” 指令如 方法调用 循环跳转 所以这些功能处指令才产生安全点

如何让线程执行到安全点,采取主动式中断的方法,当GC需要中断线程的时候,不直接对线程操作,仅仅设定一个标志,各个线程执行时主动去轮询这个标志,发现中断标志为真就自己中断线程执行,而标志和安全点是重合的,另外再加上创建对象需要分配内存的位置

——安全区域

使用Safepoint机制可以保证程序执行中,可以在不太长时间内进入GC的Safepoint。但程序不执行时,即没有分配CPU时间,如线程处于Sleep状态或Blocked状态,此时线程无法响应JVM的中断请求,而JVM不会等待线程直到分配CPU时间执行,需要另一种方法解决这种情况

安全区域是指在一段代码片段中,引用关系不会发生变化,在这个区域内的任意地方开始GC都是安全的。当线程执行到安全区域内的代码时,首先标记自己进入了安全区域,那样,当这段时间JVM要发起GC时候,就无需管该线程。在线程离开安全区域时,检查系统是否已经完成了GC根节点枚举,如果完成了,线程继续执行,否则等待离开的安全信号

猜你喜欢

转载自blog.csdn.net/qq_33369979/article/details/87891551