JDK 8 到底默认用的是哪款 GC 收集器

为啥是 JDK8?不是 9 也不是 10?因为 JDK8 还是市场占有率最高的,所以针对这个版本我做了深入的探索。

《深入理解 Java 虚拟机》第三版第 128 页中提到 JDK 9 之前,Server 默认使用 Parallel Scavenge + Serial Old(PS MarkSweep),那么真的是这样的吗? 我带着这个疑问做了如下验证

直接使用命令查看一下当前 JVM 默认参数

java -XX:+PrintCommandLineFlags -version

输入内容如下所示:

-XX:InitialHeapSize=524340992 -XX:MaxHeapSize=8389455872 
-XX:+PrintCommandLineFlags -XX:+UseCompressedClassPointers 
-XX:+UseCompressedOops -XX:+UseParallelGC
java version "1.8.0_211"
Java(TM) SE Runtime Environment (build 1.8.0_211-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.211-b12, mixed mode)

第 3 行我们可以看到使用的是 -XX:+UseParallelGC 按照书中或者是网上的文章发现,设置这个参数以后默认就是如下两个组合,新生代用 Parallel Scavenge 老年代用 Serial Old

Parallel Scavenge + Serial Old

那么这里再详细科普一下,下面是每个参数对应的回收器的类型:

参数  回收器
-XX:-UseSerialGCSerial + Serial Old
-XX:-UseParNewGCParNew + Serial Old
-XX:-UseParallelGCParallel Scavenge + Serial Old
-XX:-UseParallelOldGCParallel Scavenge + Parallel Old
-XX:-UseConcMarkSweepGCCMS + ParNew
-XX:-UseG1GCG1

用另外一个gc详情命令看一下:

java -XX:+PrintGCDetails -version

java version "1.8.0_211"
Java(TM) SE Runtime Environment (build 1.8.0_211-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.211-b12, mixed mode)
Heap
 PSYoungGen      total 150016K, used 5161K [0x0000000719500000, 0x0000000723c00000, 0x00000007c0000000)
  eden space 129024K, 4% used [0x0000000719500000,0x0000000719a0a558,0x0000000721300000)
  from space 20992K, 0% used [0x0000000722780000,0x0000000722780000,0x0000000723c00000)
  to   space 20992K, 0% used [0x0000000721300000,0x0000000721300000,0x0000000722780000)
 ParOldGen       total 343040K, used 0K [0x00000005cbe00000, 0x00000005e0d00000, 0x0000000719500000)
  object space 343040K, 0% used [0x00000005cbe00000,0x00000005cbe00000,0x00000005e0d00000)
 Metaspace       used 2207K, capacity 4480K, committed 4480K, reserved 1056768K
  class space    used 240K, capacity 384K, committed 384K, reserved 1048576K

 这里显示的是ParOldGen,从名字看无疑是Parallel Old,有点困惑。

将信将疑的我再次开启探索之旅,这时候我使用 ManagementFactory.getGarbageCollectorMXBeans() 把具体的回收器打印出来看下不就可以了吗?详细代码如下

import java.lang.management.GarbageCollectorMXBean;
import java.lang.management.ManagementFactory;
import java.util.List;
public class GcCollectorPrinter {
    public static void main(String[] args) {
        List<GarbageCollectorMXBean> beans = ManagementFactory.getGarbageCollectorMXBeans();
        for (GarbageCollectorMXBean bean : beans) {
            System.out.println(bean.getName());
        }
    }
}

直接运行输出内容如下:

PS Scavenge
PS MarkSweep

这意思是 PS MarkSweep 是 Serial Old 的意思对吗?那么 -XX:+UseParallelOldGC 打印出来的结果又是什么呢?我配置好参数再次运行如下两个命令:

javac GcCollectorPrinter.java 
java -XX:+UseParallelOldGC GcCollectorPrinter

如下是打印结果:

PS Scavenge
PS MarkSweep

等等,我更加疑惑了?-XX:+UseParallelOldGC 和  -XX:+UseParallelGC 的输出结果都是 PS MarkSweep,那么他究竟是 Serial Old 还是 Parallel Old?
这时候我有两个猜想:

  • PS MarkSweep 只是回收器的别名,他可以指代 Serial Old 和 Parallel Old,毕竟他们的实现基本一样。
  • -XX:+UseParallelGC 和 -XX:+UseParallelOldGC 结果一样,都是用的 Parallel Old

好的那么接下来开启 GC 之旅,这个"别名"一样没办法了,我直接打印一下 GC 的日志,看下日志里面显示什么,-XX:+PrintGCDetails 这个参数就上场了,他可以输出 GC 详细的分区分析,我们再次运行刚才的两个例子如下:

java -XX:+UseParallelOldGC -XX:+PrintGCDetails GcCollectorPrinter
java -XX:+PrintGCDetails GcCollectorPrinter

结果惊人的一致:

PS Scavenge
PS MarkSweep
Heap
 PSYoungGen      total 76288K, used 3932K [0x000000076ab00000, 0x0000000770000000, 0x00000007c0000000)
  eden space 65536K, 6% used [0x000000076ab00000,0x000000076aed7240,0x000000076eb00000)
  from space 10752K, 0% used [0x000000076f580000,0x000000076f580000,0x0000000770000000)
  to   space 10752K, 0% used [0x000000076eb00000,0x000000076eb00000,0x000000076f580000)
 ParOldGen       total 175104K, used 0K [0x00000006c0000000, 0x00000006cab00000, 0x000000076ab00000)
  object space 175104K, 0% used [0x00000006c0000000,0x00000006c0000000,0x00000006cab00000)
 Metaspace       used 2729K, capacity 4486K, committed 4864K, reserved 1056768K
  class space    used 297K, capacity 386K, committed 512K, reserved 1048576K

可以看到 老年代都是用的 ParOldGen 那么一点可以断定了,-XX:+UseParallelGC 和 -XX:+UseParallelOldGC 结果一样,都是用的 Parallel Old。

那么我们继续验证第二个疑问,PS MarkSweep 只是回收器的别名,他可以指代 Serial Old 和 Parallel Old,可以直接使用如下命令验证,我用的不是+而是-,这样就一定强制去掉了 Parallel Old 收集器,我们看下效果

java -XX:-UseParallelOldGC -XX:+PrintGCDetails GcCollectorPrinter
PS Scavenge
PS MarkSweep
Heap
 PSYoungGen      total 76288K, used 3932K [0x000000076ab00000, 0x0000000770000000, 0x00000007c0000000)
  eden space 65536K, 6% used [0x000000076ab00000,0x000000076aed7240,0x000000076eb00000)
  from space 10752K, 0% used [0x000000076f580000,0x000000076f580000,0x0000000770000000)
  to   space 10752K, 0% used [0x000000076eb00000,0x000000076eb00000,0x000000076f580000)
 PSOldGen        total 175104K, used 0K [0x00000006c0000000, 0x00000006cab00000, 0x000000076ab00000)
  object space 175104K, 0% used [0x00000006c0000000,0x00000006c0000000,0x00000006cab00000)
 Metaspace       used 2728K, capacity 4486K, committed 4864K, reserved 1056768K
  class space    used 297K, capacity 386K, committed 512K, reserved 1048576K

唯一的变化就是 ParOldGen 换成了 PSOldGen,经过查询我们可以确定 PSOldGen 就是  Serial Old 所以终于有了答案。

  • PS MarkSweep 只是回收器的别名,他可以指代 Serial Old 和 Parallel Old。
  • -XX:+UseParallelGC 和 -XX:+UseParallelOldGC 结果一样,都是用的 Parallel Old

然后找了一个使用jdk1.8.0_211启动的java服务,看一下它的gc日志,下面第3行的ParOldGen也证实了使用Parallel Old。

2023-11-03T00:07:22.428+0800: 714684.347:
 [Full GC (System.gc()) [PSYoungGen: 9056K->0K(16296960K)] 
[ParOldGen: 5934750K->5933554K(33554432K)] 
5943806K->5933554K(49851392K), 
[Metaspace: 395029K->395029K(420092K)], 3.397 secs] 
[Times: real=3.397 secs] [pid: 51535] 
[timestamp: 1698941242428] [node: xxx-APP010]

那书上说的还能有假?保险起见还是去找一些资料吧

在 JDK 8 的官网找到了一些蛛丝马迹
链接:https://urlify.cn/67NnEz

 Parallel compaction is enabled by default if the option 
-XX:+UseParallelGC has been specified. 
The option to turn it off is -XX:-UseParallelOldGC.

大致意思就是说-XX:+UseParallelGC 就会开始 Parallel 收集器除非手动关闭,那么可是书上为什么说是 Serial呢?

终于我在 JDK 源码 commit 记录里面找到了答案,在 JDK 7U4 之前确实 UserParallelGC 用的就是 Serial,在这个版本之后 Parallel 已经很成熟了,所以直接替换了旧的收集器,所以 JDK 7u4 以后的 7 和 JDK 8 老年代默认使用的都是 Parallel 收集器,只是书中没有更新这个细节。
网址:
https://bugs.openjdk.java.net/browse/JDK-6679764
http://hg.openjdk.java.net/jdk8u/jdk8u/hotspot/rev/24cae3e4cbaa
原文:

Server-class machine ergonomics was introduced in jdk5. 
If the machine upon which the jvm is running is powerful 
enough (currently, at least 2 physical cores plus
at least 2gb of memory), the server jvm is invoked 
using the parallel scavenger rather than the serial scavenger. 
Currently the old gen collector used is
serial mark-sweep-compact. 
Now that the parallel old gen collector is mature,
we should change to using it instead.
Issue Links

原文链接:https://blog.csdn.net/weixin_43753797/article/details/106450040

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值