我知道当新的对象分配失败或调用System.gc()时会触发GC。每个GC算法都建议,作为第一步,GC线程将挂起所有应用程序线程,以便它们不会影响GC活动。
但我想了解GC如何暂停所有正在运行的线程?我的意思是JVM定义了任何安全点,例如,内存分配(新对象创建)或方法调用,当应用程序线程到达这些安全点时,它们将被阻止以防止GC锁定。这是真的吗?如果是这样,那么一个只进行如下简单计算的应用程序线程怎么样(我知道这实际上永远不会发生),它会被暂停吗?
while(true) {
a = a + s;
s = s + a;
// some computation that doesn't touch any JVM safe points
}
在这些情况下,GC活动是否会在不挂起这些应用程序线程的情况下继续(并在以后尝试跨越安全点时暂停/阻止,例如对象分配)?
但我相信,GC始终等待这些应用程序线程进入安全点并在继续之前暂停它们。我的假设是真的吗?
答案 0 :(得分:5)
但我想了解GC如何暂停所有正在运行的线程?
热点实施使用safepoint polling。引用:
来自机械同情邮件列表的安全点如何运作?
HotSpot JVM中的安全点协议是 协作。每个应用程序线程检查安全点状态和 需要将自己停放在安全状态的安全状态。对于编译代码, JIT在某些点(通常是在之后)插入代码中的安全点检查 从呼叫返回或在循环的后跳)。对于解释代码,JVM 有两个字节的代码调度表,如果需要safepoint,则为JVM 切换表以启用安全点检查。
安全点状态检查 本身是以非常狡猾的方式实现的。正常的记忆变量 检查需要昂贵的记忆障碍。虽然,安全点检查 实现为内存读取障碍。然后需要安全点, JVM取消映射该地址,导致应用程序出现页面错误 线程(由JVM的处理程序处理)。这样,HotSpot 保持其JITed代码CPU管道友好,但确保正确 内存语义(页面unmap强制内存屏障处理 芯)。
// some computation that doesn't touch any JVM safe points
如果编译器可以证明它们在有限的时间内完成,那么编译器只允许这些事情。否则它会插入安全点轮询