From:深入理解Java虚拟机
- 目录
BiBi - JVM -0- 开篇
BiBi - JVM -1- Java内存区域
BiBi - JVM -2- 对象
BiBi - JVM -3- 垃圾收集算法
BiBi - JVM -4- HotSpot JVM
BiBi - JVM -5- 垃圾回收器
BiBi - JVM -6- 回收策略
BiBi - JVM -7- Java类文件结构
BiBi - JVM -8- 类加载机制
BiBi - JVM -9- 类加载器
BiBi - JVM -10- 虚拟机字节码
BiBi - JVM -11- 编译期优化
BiBi - JVM -12- 运行期优化
BiBi - JVM -13- 并发
问题1:GC Roots节点寻找引用链耗时,并且该分析要保证一致性,即不会出现分析过程中对象引用关系还在不断变化的情况,该如何?
GC进行时必须停顿所有Java线程 — Stop The World。
GC Roots节点主要在全局性的引用【常量或类静态属性】和执行上下文【栈桢中的本地变量表】中。但,并不需要一个不漏地检查完所有全局的引用和执行上下文,HotSpot使用OopMap的数据结构,在类加载完成的时候,HotSpot就把对象内什么偏移量上是什么类型的数据都计算出来,在JIT编译过程中,也会在特定的位置记录栈和寄存器中哪些位置是引用。所以通过OopMap,GC在扫描时就可以直接得知这些信息。
问题2:在OopMap的协助下,HotSpot可以快速且准确的完成GC Roots枚举,但如果为每一条指令都生成对应的OopMap,GC的空间成本将会很高?
要在特定的位置记录这些信息,这些位置称为【安全点,Safepoint】,即程序执行时并非在所有地方都停顿下来开始GC,只有在到达安全点时才可以。具有产生安全点指令的功能有:方法调用、循环跳转、异常跳转等。
安全点的选定既不能太少以致于让GC执行时间太长;也不能过于频繁以致于增大运行负荷。
问题3:GC发生时,如何让所有【不包括JNI线程】线程都“跑”到最近的安全点上再停顿下来?
采用【主动式中断】的思想:当GC需要中断线程时,不直接对线程操作,而是简单的设置一个标志,各个线程执行时主动去轮询这个标志,发现中断标志为真时就中断挂起,轮询标志的地方和安全点是重合的,跟创建对象需要分配内存的地方也是重合的。
问题4:当线程处于Sleep状态或Blocking状态时,线程无法响应JVM的中断请求,从而线程不能“走”到安全点的地方进行中断挂起,该如何?
【安全区域,Safe Region】一段代码片段中,引用关系不会发生变化,在这个区域中的任意地方开始GC都是安全的。
在线程执行到Safe Region中的代码时,会标识自己已经进入到Safe Region,当JVM发起GC时,就不用管标识自己为Safe Region状态的线程了。当线程要离开Safe Region时,会检测系统是否完成了GC过程,如果完成了,线程就会继续执行,否则它必须等待直到收到可以离开Safe Region的信号为止。
网友评论