JVM

一文讲清楚 JVM Safe Point

Posted by 陈树义 on 2022-10-08

大家好,我是树哥。

关于 Safe Point 是 JVM 中很关键的一个概念,但我估计有不少同学不是很懂。于是今天跟大家来深入聊聊 Safe Point,希望通过这篇文章能解答这样几个问题:

  1. 什么是 Safe Point?
  2. 为啥需要 Safe Point?
  3. Safe Point 与 Stop the World 的关系?

什么是 Safe Point

正如 Safe Point 名称的寓意一样,Safe Point 是一个线程可以安全停留在这里的代码点。当我们需要进行 GC 操作的时候,JVM 可以让所有线程在 Safe Point 处停留下来,等到所有线程都停在 Safe Point 处时,就可以进行内存引用分析,从而确定哪些对象是存活的、哪些对象是不存活的。

为什么让大家更加场景化地理解 Safe Point 这个概念,可以设想如下场景:

  1. 当需要 GC 时,需要知道哪些对象还被使用,或者已经不被使用可以回收了,这样就需要每个线程的对象使用情况。
  2. 对于偏向锁(Biased Lock),在高并发时想要解除偏置,需要线程状态还有获取锁的线程的精确信息。
  3. 对方法进行即时编译优化(OSR 栈上替换),或者反优化(bailout 栈上反优化),这需要线程究竟运行到方法的哪里的信息。

对于上面这些操作,都需要知道现场的各种信息,例如寄存器有什么内容,堆使用情况等等。在做这些操作的时候,线程需要暂停,等到这些操作完成才行,否则会有并发问题,这就需要 Safe Point 的存在。

因此,我们可以将 Safe Point 理解成代码执行过程中的一些特殊位置,当线程执行到这个位置时,线程可以暂停。 Safe Point 处保存了其他位置没有的一些当前线程信息,可以提供给其他线程读取,这些信息包括:线程上下文信息,对象的内部指针等。

而 Stop the World 就是所有线程同时进入 Safe Point 并停留在那里,等待 JVM 进行内存分析扫描,接着进行内存垃圾回收的时间。

为啥需要 Safe Point

前面我们说到,Safe Point 其实就是一个代码的特殊位置,在这个位置时线程可以暂停下来。而当我们进行 GC 的时候,所有线程都要进入到 Safe Point 处,才可以进行内存的分析及垃圾回收。根据这个过程,其实我们可以看到:Safe Point 其实就是栅栏的作用,让所有线程停下来,否则如果所有线程都在运行的话,JVM 无法进行对象引用的分析,那么也无法进行垃圾回收了。

此外,另一个重要的 Java 线程特性 —— interrupted 也是根据 Safe Point 实现的。当我们在代码里写入 Thread.interrupt() 时,只有线程运行到 Safe Point 处时才知道是否发生了 interrupted。因此,Safe Point 也承担了存储线程通信的功能。

总结

简单地说,Safe Point 就是人为规定出的一些代码位置,在这些位置上线程可以暂停下来,从而让 JVM 可以进行内存对象引用分析等操作。此外,Safe Point 处也会存储一些特殊的信息,从而支持 Java 的某些特性,例如:Java 的 interrupt 特性需要到 Safe Point 处才能知道。

其实关于 Safe Point 的内容还有不少,例如:

  1. 什么地方会放 Safe Point?
  2. Safe Point 具体是怎么实现的?
  3. 什么情况会让所有线程进入 Safe Point?

但对于大多数应用开发人员来说,其实暂时不需要了解得这么深,只需要知道啥是 Safe Point 以及其存在的价值即可。如果你对这些问题感兴趣,可以通过参考资料部分详细了解。

参考资料