简介
java 程序员都听说过 GC,大家也都知道 GC 的目的是扫描堆空间,然后将那些标记为删除的对象从堆空间释放,以提升可用的堆空间。今天我们会来探讨一下隐藏在 GC 背后的一个小秘密 Safepoints。
GC 的垃圾回收器
小师妹:F 师兄,GC 的垃圾回收器的种类为什么会有这么多呀?使用起来不是很麻烦。并且我听说 CMS 在 JDK9zhong 已经被废弃了。
小师妹,这么多垃圾回收器实际是在 JVM 的发展过程中建立起来的,在之前的文章中,我们讲到了目前的 GC 回收器有这样几种。
- 基于分代技术的回收器
Concurrent mark sweep (CMS),CMS 是 mark and swap 的升级版本,它使用多个线程来对 heap 区域进行扫描,从而提升效率。
由于 CMS 的参数复杂性和性能问题,CMS 已经在 JDK9 中被废弃了。
Serial garbage collection,使用单一的线程来进行垃圾回收操作,其好处就是不需要和其他的线程进行交互。如果你是单核的 CPU,那么最好就是选择 Serial garbage collection,因为你不能充分利用多核的好处。同样的它也常常用在比较小型的项目中。
Parallel garbage collection,如果你是多核处理器,那么 Parallel GC 可能是你的选择。
Parallel GC 是 JDK8 中的默认 GC。而在 JDK9 之后,G1 是默认的 GC。
G1 garbage collection,G1=Garbage First,它是为替换 CMS 而生的,最早出现在 java7 中。
G1 将 heap 区域划分成为多个更小的区域,每个小区域都被标记成为 young generation 或者 old generation。从而运行 GC 在更小的范围里运行,而不是影响整个 heap 区域。
- 非基于分代技术的回收器
Z Garbage Collection,ZGC 是一个可扩展的,低延迟的 GC。ZGC 是并发的,而且不需要停止正在运行的线程。
ZGC 是在 JDK11 中引入的。
当然还有正在研发中的其他 GC。
更多精彩内容且看:
- 区块链从入门到放弃系列教程 - 涵盖密码学, 超级账本, 以太坊,Libra, 比特币等持续更新
- Spring Boot 2.X 系列教程: 七天从无到有掌握 Spring Boot- 持续更新
- Spring 5.X 系列教程: 满足你对 Spring5 的一切想象 - 持续更新
- java 程序员从小工到专家成神之路(2020 版)- 持续更新中, 附详细文章教程
分代回收器中的问题
小师妹:F 师兄,分代回收器不好吗?为什么还有新的 ZGC 等基于非分代技术的回收器?
分代垃圾回收器中有一个非常常见的现象就是 ”Stop The World”。什么是 Stop the world 呢?
就是说在 GC 的时候,为了进行垃圾回收,需要所有的线程都要暂停执行。所有的线程都暂停执行。
当然 G1 虽然是基于分代技术,但是 G1 实际上是不会 ”Stop The World” 的。
JVM 定义了一些 Root 对象,从这些对象开始,找出他们引用的对象,组成一个对象图。所有在这个图里面的对象都是有效的对象,反之不在对象图中的对象就应该被回收。有效的对象将会被 Mark 为 alive。
这些 Root 对象包括:正在执行的方法中的本地对象和输入参数。活动的线程,加载类中的 static 字段和 JNI 引用。
safepoints
为了实现 STW 的功能,JVM 需要提供一个机制,让所有的线程可以在某一个时刻同时停下来。这个停下来的时刻就叫做 safepoints。
注意,这些停下来的线程不包括运行 native code 的线程。因为这些线程是不属于 JVM 管理的。
JVM 中的代码执行其实有两种方式,一种是 JIT 编译成为机器码,一种是解释执行。
在 JIT 中,直接将检查代码编译进入了机器码中。通过设置相应的标记位,从而在线程运行的过程中执行暂停的指令。
还是举一个上篇文章中我们提到的 JMH 的例子:
@Benchmark
public void test1() {
int length = array.length;
for (int i = 0; i < length; i=i+1)
array[i] ++;
}
我们看一下它的 assembly code:
可以看到其中有个 test 的指令,这个 test 指令就是生成的 safe points。
通过设置标志位,就可以在线程运行时执行暂停操作。
如果是解释执行的话,JVM 保存了两个字节码的调度 table,当需要 safepoint 的时候,JVM 就进行 table 的切换,从而开启 safepoint。
safepoint 一般用在什么地方
一般情况下,GC,JIT 的反代码优化,刷新 code cache, 类重定义 , 偏向锁撤销和其他的一些 debug 操作。
我们可以通过使用 -XX:+PrintGCApplicationStoppedTime 来 print safepints 的暂停时间。
-XX:+PrintSafepointStatistics –XX:PrintSafepointStatisticsCount= 1 这两个参数可以强制 JVM 打印 safepoint 的一些统计信息。
总结
Safepoint 是垃圾回收中一个非常重要的概念,希望大家能够有所了解。
本文作者:flydean 程序那些事
本文链接:http://www.flydean.com/jvm-jit-safepoints/
本文来源:flydean 的博客
欢迎关注我的公众号: 程序那些事,更多精彩等着您!