《深入理解JVM》第三章 垃圾收集器与内存分配策略(HotSpot算法实现)

版权声明:版权为ZZQ所有 https://blog.csdn.net/qq_39148187/article/details/81808284

枚举根节点

可达性分析从GC Roots 节点着引用链这个操作为例,可作为GC Roots 的节点主要在全局性的引用(常量或者类静态属性)与执行上下文(栈帧的本地变量表)中,现在很多应用仅仅方法区就有数百兆,如果要逐个检查这里面的引用那么必然会消耗很多时间

另外,可达性分析的执行时间敏感还体现在GC停顿上,因为这项分析工作必须在一个能确保以一致性的快照中进行---这里的以执行指的是在分析期间执行系统就像冻结在某一个时间点上,不可出现分析过程中对象的关系还是不断的变换情况,该点不满足的化分析结果准确性就无法得到保证,这是导致GC进行中必须停顿所有java 执行线程的其中一个重要原因,即使在号称不会发生停顿的CMS收集器中枚举节点还是必须要停顿的

目前主流的java 虚拟机都是使用准确式GC,所以当执行系统停顿下后,并不需要一个不露的检查完所有执行上下文的全局引用位置,虚拟机应当是有办法直接的值哪些地方存放对象的引用,在hotspot 的实现中,是使用一组成为OopMap的数据结构来达到这个目的的,在类加载完毕的时候,HotSpot就把对象内什么偏移量上是什么类型的数据计算出来,JIT编译过程中也会在特定的位置记录下栈和寄存器中那些位置是引用的,这样GC再扫描的时候就直接得到这些消息,

https://www.cnblogs.com/strinkbug/p/6376525.html?

安全点

在OopMap 的协助下 HotSpot可以快速且准确的完成GCRoots枚举,但一个很现实的问题随之而来,这可能导致引用关系的变换,或者说OopMap内容变化和指令非常多,如果每一条指令都对应生成对应的OopMap 呢会需要大量的额外内存空间,Gc的空间成本就会变得很高,

事实上Hotspot 也的确没有为每条指令都声称OopMap ,只是在特定的地点记录了这些信息,只有到达安全点(Safepoint)才能暂停,SafePoint选定既不能太少,以至于Gc等待的时间太长,也不能频繁以至于过分增大运行的符合,所以安全点的选定基本上是以程序 是否具有让程序长时间执行的特性,为标准进行选定的,因为每条指令执行的时间都是非常短的,程序不太可能因为指令流长度太长原因而长时间运行,长时间运行明显特征就是指令序列复用,比如方法调用,循环跳转,异常跳转,所以这些具有功能的指令才会产生safepoint

对于Sefepoint 另一个考虑的问题是如何GC发生时让所有线程跑到最近的安全点停下来,1.抢先式中断,2.主动中断,

抢先式中断

不需要线程的执行代码去主动配合,GC发生时,首先把所有线程全部中断,如果发现线程终端不在安全点, 就恢复先线程让他跑到安全点,但是现在没有虚拟机用这种

主动式中断

就是不对线程进行操作,仅仅设置一个标志,各个线程执行时主动去轮询这个标志,发现中断标志就把自己挂起来,轮询标志的地方是和安全点重合的,另外加上创建对象需要分配的内存的地方

安全区域

使用Safepoint 似乎完美的解决了进入GC问题,但是实际情况不是这样,Safepoint 机制保证了程序执行时,在不太长的时间就会遇到GC的Safepoint,但如果程序不执行的时候怎么办? 所谓程序执行就是没有分配CPU时间,典型的例子就是处于Sleep状态和Blocked 状态,这个时候西安城无法相应JVM的中断请求,走到安全的地方中断挂起,JVM也显然不可能等待线程重新分配CPU,这个时候需要安全区解决(Safe Region)

安全区是指一段代码之中,引用关系不会发生变化,在这个区域中任何一个点进行GC都是安全的,Safe region 看出是可拓展的Safepoint 

当JVM要进行GC的时候,不用管在Safe region 中的线程,线程出Safe region 的时候会自动检测是否完成了根节点枚举(或者是完成了gc的整个过程,)如果完成了线程就继续执行,如果没有就等待可以安全离开Safe region 的信号为止 

猜你喜欢

转载自blog.csdn.net/qq_39148187/article/details/81808284