一文讲清楚 JVM Safe Point
阅读原文时间:2023年07月09日阅读:1

大家好,我是树哥。

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

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

正如 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 其实就是一个代码的特殊位置,在这个位置时线程可以暂停下来。而当我们进行 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 以及其存在的价值即可。如果你对这些问题感兴趣,可以通过参考资料部分详细了解。