本文主要是介绍GC-STW-SafePoint,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
Safepoint 可以理解成是在代码执行过程中的一些特殊位置,当线程执行到这些位置的时候,线程可以暂停。在 SafePoint 保存了其他位置没有的一些当前线程的运行信息,
供其他线程读取。这些信息包括:线程上下文的任何信息,例如对象或者非对象的内部指针等等。我们一般这么理解 SafePoint,就是线程只有运行到了 SafePoint 的位置,
他的一切状态信息,才是确定的,也只有这个时候,才知道这个线程用了哪些内存,没有用哪些;并且,只有线程处于 SafePoint 位置,这时候对 JVM 的堆栈信息进行修改
GC 一定需要所有线程同时进入 SafePoint,并停留在那里,等待 GC 处理完内存,再让所有线程继续执。像这种**所有线程进入 SafePoint **等待的情况,就是 Stop the world
在 SafePoint 位置保存了线程上下文中的任何东西,包括对象,指向对象或非对象的内部指针,在线程处于 SafePoint 的时候,对这些信息进行修改,线程才能感知到。所以,只有线程处于 SafePoint 的时候,才能针对线程使用的内存进行 GC,以及改变正在执行的
SafePoint 实现相关源代码
操作触发了某个 VM 线程所有线程需要进入 SafePoint(例如现在需要 GC),如果其他线程现在:
1 运行字节码:运行字节码时,解释器会看线程是否被标记为 poll armed,如果是,VM 线程调用 SafepointSynchronize::block(JavaThread *thread)进行 block
2 运行 native 代码:当运行 native 代码时,VM 线程略过这个线程,但是给这个线程设置 poll armed,让它在执行完 native 代码之后,它会检查是否 poll armed,如果还需要停在 SafePoint,则直接 block。
3运行 JIT 编译好的代码:由于运行的是编译好的机器码,直接查看本地 local polling page 是否为脏,如果为脏则需要 block
4处于 BLOCK 状态:在需要所有线程需要进入 SafePoint 的操作完成之前,不许离开 BLOCK 状态
5处于线程切换状态或者处于 VM 运行状态:会一直轮询线程状态直到线程处于阻塞状态(线程肯定会变成上面说的那四种状态,变成哪个都会 block 住)。
哪些情况下会让所有线程进入 SafePoint, 即发生 Stop the world?
1定时进入 SafePoint
2由于 jstack,jmap 和 jstat 等命令,也就是 Signal Dispatcher 线程要处理的大部分命令,都会导致 Stop the world
3偏向锁取消(这个不一定会引发整体的 Stop the world)
4Java Instrument 导致的 Agent 加载以及类的重定义
5Java Code Cache相关:当发生 JIT 编译优化或者去优化,需要 OSR 或者 Bailout 或者清理代码缓存的时候
6GC:这个由于需要每个线程的对象使用信息,以及回收一些对象,释放某些堆内存或者直接内存,所以需要 Stop the world
7JFR 的一些事件:如果开启了 JFR 的 OldObject 采集,这个是定时采集一些存活时间比较久的对象,所以需要 Stop the world
什么情况会导致 Stop the world 时间过长?
1 Stop the world 阶段可以简单分为(这段时间内,JVM 都是出于所有线程进入 Safepoint 就 block 的状态):某个操作,需要 Stop the world(就是上面提到的哪些情况下会让所有线程进入 SafePoint, 即发生 Stop the world 的那些操作)
2 向 Signal Dispatcher 这个 JVM 守护线程发起 Safepoint 同步信号并交给对应的模块执行。
3 对应的模块,采集所有线程信息,并对每个线程根据状态做不同的操作以及标记(根据之前源代码那一块的描述,有5种情况)
4所有线程都进入 Safepoint 并 block。
5做需要发起 Stop the world 的操作。
6操作完成,所有线程从 Safepoint 恢复。
这篇关于GC-STW-SafePoint的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!