JVM如何发起内存回收问题

1.分析、枚举根节点(GC Roots)

GC时枚举根节点时必须停顿;

原因:枚举根节点是可达性分析中从GC Roots节点找引用链这个操作为例,可作为GC Roots的节点主要在全局性引用(例如 常量 或 静态属性)与 执行上下文(例如栈帧中的本地变量表)中,逐个检查这里的引用,必然会消耗很多时间,可达性分析对执行时间的敏感还体现在GC停顿上,这项分析工作必须在一个能确保一致性的快照中进行,这里"一致性"的意思就是分析期间整个执行系统看起来就像呗冻结在某个时间点上。

目前主流Java虚拟机使用的是 准确式GC,在HotSpot的实现中,使用组称为OopMap的数据结构来达到这个目的

2.安全点 

安全点:程序执行时并非在所有地方都能停顿下来开始GC,只有到达安全点(Safepoint)时才能暂停。

问题:如何在GC发生时让所有线程都"跑"到最近的安全点上再停顿下来?

方案1:抢先式中断(Preemptive Suspension)不需要线程的执行代码主动去配合,在GC发生时,首先把所有线程全部中断,如果发现有线程中断的地方不在安全点上,就恢复线程,让它"跑"到安全点上,目前几乎没有虚拟机采用抢先式中断来暂停线程来响应GC时间

方案2:主动是中断(Voluntary Suspension)是当GC需要中断线程时,不直接对线程操作,仅仅简单地设置一个标志,各个线程执行时主动去轮询这个标志,发现中单标志位真时就自己中断挂起,轮询标志的地方和安全点是重合的

安全区域

安全点问题:如果程序"不执行"呢?就是没有分配CPU时间,例如线程处于Sleep状态或是Blocked状态,这时线程无法响应JVM的中断请求,“走”到安全的地方去中断,JVM也显然不太可能等待线程重新被分配CPU时间。

解决:对于安全点的问题就需要 安全区域(Safe Region)解决

定义:指在一段代码片段中,引用关系不会发生变化。在这个区域中的任意地方开始GC都是安全的,可以吧Safe Region看做是被扩展了的SafePoint。

过程:在线程执行到Safe Region中的代码时,首先标识自己已进入了Safe Region,这样当这段时间JVM要发起GC时,就不用管标识自己为Safe Region状态的线程了。在线程要离开Safe Region时,它要检查系统是否已经完成了根节点枚举(或是整个GC过程),如果完成了,线程继续执行,否则就必须等待直到收到可以安全离开Safe Region的信号为止

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容