服务粉丝

我们一直在努力
当前位置:首页 > 财经 >

我C,发现了《深入理解 Java 虚拟机》这本书的 BUG,胆小慎入

日期: 来源:玉刚说收集编辑:码匠笔记

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


本篇文章是之前规划的《和我一起读书吧》系列文章。

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

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

  1. 直接使用命令查看一下当前 JVM 默认参数
java -XX:+PrintCommandLineFlags -version

输入内容如下

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

第 6 行我们可以看到使用的是 -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

将信将疑的我再次开启探索之旅,这时候我使用 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 MarkSweepSerial Old 的意思对吗?那么 -XX:+UseParallelOldGC 打印出来的结果又是什么呢?我配置好参数再次运行如下两个命令

javac GcCollectorPrinter.java 
java -XX:+UseParallelOldGC GcCollectorPrinter

如下是打印结果

PS Scavenge
PS MarkSweep

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

  1. PS MarkSweep 只是回收器的别名,他可以指代 Serial OldParallel Old,毕竟他们的实现基本一样。
  2. -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 OldParallel 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 所以终于有了答案。

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

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

在 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

最近在重读《深入理解 Java 虚拟机》第三版,先后看了三次,每次感触都不一样,如果你也和我一样对 Java 虚拟机有兴趣,赶紧把书读起来吧。

相关阅读

  • flutter:一个bug的源码分析

  • 由一个bug引发的flutter的widget跟element关系的源码分析bug现象在页面本来有照片数据的(第一张照片数据),点击加号唤起系统拍照功能后,再返回页面A,原来的照片数据丢失了(部分And
  • Android 技术面试如何做好准备?

  • 这是 JsonChao 的第 210 期分享超友们,早上好,中秋节快乐~今天的干货来点轻松一点的,这次的分享是《技术面试如何做好准备?》,主要分为三个部分:第一部分:面试前。第二部分:面试中。
  • 芳芳频道|李艳芳三套卷复盘(数三①)

  • 往期直达数一复盘(已完结)数二复盘(已完结)李艳芳三套卷划重点数三第一套总体作为数三的第一套,自我感觉还是比较恰当的,整体计算量不大,概率题都很常规,较好得分,高数题和线代题不乏
  • 新文速递 - 9.22/9.29

  • 纳米粒子修饰的微型机器人用于治疗急性细菌性肺炎的体内抗生素递送Biohybrid microrobots consisting of nanoparticle-modified microalgae are constructed for active dr
  • 新文速递:11.28-12.2

  • 基于二甲基铵阳离子添加剂的中间相工程用于稳定钙钛矿太阳能电池The stability of halide perovskite solar cells, determined by film morphology, is paramount to their

热门文章

  • “复活”半年后 京东拍拍二手杀入公益事业

  • 京东拍拍二手“复活”半年后,杀入公益事业,试图让企业捐的赠品、家庭闲置品变成实实在在的“爱心”。 把“闲置品”变爱心 6月12日,“益心一益·守护梦想每一步”2018年四

最新文章

  • 探索Android开源框架 - ARouter使用及源码解析

  • 最近对项目进行组件化重构,要进行组件化就少不了组件间通信的路由,于是就再次研究了一下阿里的ARouter,关于组件化可以查看我之前写的组件化架构系列文章,这里就不过多提及了
  • 聊一聊 AS 的一些好用的功能

  • 文章开始前先墨迹几句,好久没写文章了,这段时间公司确实挺忙,也没抽出时间,上一篇文章还是三月初写的,距今已经两个多月啦,不能再这样下去了,虽然我不能像一些大佬那样周更、甚至日
  • 漫画:为什么程序员没有女朋友?

  • 原因一,程序员实在太忙了在很多互联网公司,程序员996是常态,而且就算在业余时间,程序员也需要经常看书看源码,或者是访问某个全球最大的同性交友网站......他们忙着提升自己的技