JVM内存管理—内存回收—枚举与一致性

在可达性分析之前面临的问题

可达性分析的时间敏感性,主要体现在搜索根节点,以及引用一致性

  1. 搜索根节点:可作为GC Roots的节点主要在全局性的引用上常量与静态属性)与执行上下文栈中的本地变量表)中,但是对于大型应用,在方法区的空间大小就有几百兆,每次搜索所有 GC Roots 时都将耗费大量的时间
  2. GC停顿:每次进行可达性分析时都需要保证在分析过程中引用关系的保持不变(引用一致性),这就导致进行GC时必须暂停所有java执行线程,即使在号称不会发生GC停顿的CMS收集器中,枚举根节点时用户线程也是必须要停顿的

为了改善上述的性能问题

OopMap(Ordinary object Pointer Map 普通对象指针 Map数据结构)

HotSpot JVM 在特定的位置存储栈和寄存器中哪些位置是引用,这样就不用每次GC时都去遍历这些区域,节省了大量时间。

Safepoint(安全点)
  • 当需要GC时,程序执行时并非在所有地方都能停顿下来进行GC,只有到达安全点时才能暂停。
  • 理论上OopMap为了能在任意位置进行暂停GC,必须为每条命令生成对应的OopMap对象,这将需要大量的空间,GC空间成本将会增加,实际上HotSpot只会在安全点生成对应的OopMap来记录这些引用。

GC发生时,应用程序如何暂停?

  • 抢先式暂停:不需要线程的执行代码进行配合,而是在GC时直接中断暂停,然后判断哪个线程没有落在安全点上,如果没有落在安全点则恢复线程使其运行到最近的安全点上。
  • 主动式暂停:设置一个标志,每个线程执行到安全点或者创建对象需要分配内存空间的时候主动轮询这个标志,发现为中断标志时使自己中断挂起。这是所有JVM的主要实现方式
Safe Region(安全区域)
  • 为了解决处于sleep和blocked状态的线程没有办法响应JVM的中断请求(或者主动轮询中断标志),始终没有办法走到安全点
  • 安全区指的是一段代码之中,引用关系不会发生变化,在这个区域中的任意地方开始对这个线程 GC 都是安全的。

过程

  • 在线程执行到Safe Region的代码时,首先标识自己已经进入了Safe Region,然后线程可以继续运行,在这期间可以sleep或者blocked,但是离开安全区域必须检查系统是否已经完成了根节点的枚举或者是整个GC过程,如果为是,则离开,否则等待直到为是。
  • 由于线程sleep或blocked时引用关系不再变化,而引用关系不再的变化的代码位于安全区域,换句话说sleep或blocked总是在安全区域内,所以GC时不用使sleep或blocked的线程跑到安全点上,因为位于安全区域的线程不管状态如何,都能保证在这段时间内引用是不在变化的。

总结

  • 每个安全点、安全区域指的是某一个线程执行的位置和区间,当发生GC时,每个线程都到达各自对应的最近的安全点或安全区域,就可以保证引用一致性了。
  • JVM负责设置中断和恢复安全点的所有线程,GC 面向的是所有线程
  • 可达性分析后进行回收时线程是继续执行还是暂停取决于垃圾收集器的执行方式(并行还是串行的)

你可能感兴趣的:(JVM内存管理—内存回收—枚举与一致性)