JVM的很多参数命名很有迷惑性,-XX:+UseParallel-XX:+UseParallelOldGC-XX:+UseParNewGC-XX:+UseConcMarkSweepGC咋一看容易混淆,而且JDK升个级某个GC就可能不见了,为了详细了解这些参数的区别,先来看看到底都有哪些类型的GC:

  1. // hotspot\share\gc\shared\gc_globals.hpp
  2. product(bool, UseConcMarkSweepGC, false,
  3. "Use Concurrent Mark-Sweep GC in the old generation")
  4. product(bool, UseSerialGC, false,
  5. "Use the Serial garbage collector")
  6. product(bool, UseG1GC, false,
  7. "Use the Garbage-First garbage collector")
  8. product(bool, UseParallelGC, false,
  9. "Use the Parallel Scavenge garbage collector")
  10. product(bool, UseParallelOldGC, false,
  11. "Use the Parallel Old garbage collector")
  12. experimental(bool, UseEpsilonGC, false,
  13. "Use the Epsilon (no-op) garbage collector")
  14. experimental(bool, UseZGC, false,
  15. "Use the Z garbage collector")

好消息是ParNewGCJDK9中弃用了,JDK10中已经完全移除了,它的理想代替物是G1GC。然后openjdk12中现存的GC有:

  • ConcMarkSweepGC
  • SerialGC
  • G1GC
  • ParallelGC
  • EpsilonGC
  • ZGC
  • ShenandoahGC ( OpenJDK12上游的新GC,我的源码拉的早,就没有它了)

它们在源码中都有对应的独立目录:

  1. λ tree .
  2. ├─gc
  3. ├─cms # UseConcMarkSweepGC
  4. ├─epsilon # UseEpsilonGC
  5. ├─g1 # UseG1GC
  6. ├─parallel # UseParallelGC && UseParallelOldGC
  7. ├─serial # UseSerialGC
  8. ├─shared # 所有GC共享的代码
  9. └─z # UseZGC

本文将要简要分析Parallel GC和ParallelOld GC的区别。

要想找不同很简单:对着源码目录搜索一下UseParallelGC/UseParallelOldGC标志,可以得到所有源码的引用,而且找出来的结果通常是两者伴随出现的,看来方法是没问题的。重点关注几个地方,parallelArgument.cpp它会负责GC早期的参数处理(可以参见EpsilonGC示例):

  1. // hotspot\share\gc\parallel\parallelArguments.cpp
  2. void ParallelArguments::initialize() {
  3. GCArguments::initialize();
  4. assert(UseParallelGC || UseParallelOldGC, "Error");
  5. // Enable ParallelOld unless it was explicitly disabled (cmd line or rc file).
  6. if (FLAG_IS_DEFAULT(UseParallelOldGC)) {
  7. FLAG_SET_DEFAULT(UseParallelOldGC, true);
  8. }
  9. FLAG_SET_DEFAULT(UseParallelGC, true);
  10. ...
  11. }

这段代码告诉我们,除非显式指定-XX:-UseParallelOldGC,否则都开启Parallel Old。第二个地方是GCConfiguration:

  1. // hotspot\share\gc\shared\gcConfiguration.cpp
  2. GCName GCConfiguration::young_collector() const {
  3. if (UseG1GC) {
  4. return G1New;
  5. }
  6. // 如果开启UseParallelGC则新年代使用ParallelScavenge
  7. if (UseParallelGC) {
  8. return ParallelScavenge;
  9. }
  10. if (UseConcMarkSweepGC) {
  11. return ParNew;
  12. }
  13. if (UseZGC) {
  14. return NA;
  15. }
  16. return DefNew;
  17. }
  18. GCName GCConfiguration::old_collector() const {
  19. if (UseG1GC) {
  20. return G1Old;
  21. }
  22. if (UseConcMarkSweepGC) {
  23. return ConcurrentMarkSweep;
  24. }
  25. // 如果开启UseParallelOldGC则老年代使用ParallelOld,否则使用SerialOld
  26. if (UseParallelOldGC) {
  27. return ParallelOld;
  28. }
  29. if (UseZGC) {
  30. return Z;
  31. }
  32. return SerialOld;
  33. }

通过简单的字符串搜索就能知道:

  • +UseParallelGC = 新生代ParallelScavenge + 老年代ParallelOld
  • +UseParallelOldGC = 同上
  • -UseParallelOldGC = 新生代ParallelScavenge + 老年代SerialOld

ParallelOld和SerialOld字面上意思是老年代并行处理和老年代串行处理,关于这两个的区别也可以通过字符串搜索一窥究竟:

  1. //hotspot\share\gc\parallel\parallelScavengeHeap.cpp
  2. void ParallelScavengeHeap::do_full_collection(bool clear_all_soft_refs) {
  3. if (UseParallelOldGC) {
  4. bool maximum_compaction = clear_all_soft_refs;
  5. // ParallelOld使用PSParallelCompact做full gc
  6. PSParallelCompact::invoke(maximum_compaction);
  7. } else {
  8. // 关闭ParallelOld则使用PSMarkSweep做full gc
  9. PSMarkSweepProxy::invoke(clear_all_soft_refs);
  10. }
  11. }

PSMarkSweepProxy是一个命名空间,它做的唯一一件事情就是把调用转发到PSMarkSweep类的同名方法,比如PSMarkSweepProxy::do_a()实际调用的是PSMarkSweep::do_a()。PSMarkSweep和Serial GC Full GC提到的算法几乎一样,都是串行地分四个阶段对老年代做标记-压缩,稍有不同的是PSMarkSweep支持UseAdaptiveSizePolicy参数,它可以自适应的调整新生代和老年代的大小。

总的来说,Parallel GC和Parallel Old GC说的是不一样的事情,前者表示并行分代式垃圾回收器,其老年代和新生代都是多线程并行操作。而后者只是老年代是否使用并行的一个选项(默认开启),如果关闭则老年代退化为串行操作。之所以这样是因为早期HotSpot的并行GC只支持新生代并行,老年代的并行是后面版本加入的。

最后,附上所有垃圾回收器名和对应的分代名:

垃圾回收器 新生代名 老年代名
G1GC G1New G1Old
Parallel GC ParallelScavenge ParallelOld(-UseParallelOld则是SerialOld)
CMS ParNew ConcurrentMarkSweep
Serial GC DefNew SerialOld
Epsilon N/A N/A
ZGC N/A Z
Shenandoah N/A Shenandoah

[Inside HotSpot] UseParallelGC和UseParallelOldGC的区别的更多相关文章

  1. [Inside HotSpot] C1编译器HIR的构造

    1. 简介 这篇文章可以说是Christian Wimmer硕士论文Linear Scan Register Allocation for the Java HotSpot™ Client Compi ...

  2. [Inside HotSpot] C1编译器优化:全局值编号(GVN)

    1. 值编号 我们知道C1内部使用的是一种图结构的HIR,它由基本块构成一个图,然后每个基本块里面是SSA形式的指令,关于这点如可以参考[Inside HotSpot] C1编译器工作流程及中间表示. ...

  3. [Inside HotSpot] C1编译器优化:条件表达式消除

    1. 条件传送指令 日常编程中有很多根据某个条件对变量赋不同值这样的模式,比如: int cmov(int num) { int result = 10; if(num<10){ result ...

  4. [inside hotspot] 汇编模板解释器(Template Interpreter)和字节码执行

    [inside hotspot] 汇编模板解释器(Template Interpreter)和字节码执行 1.模板解释器 hotspot解释器模块(hotspot\src\share\vm\inter ...

  5. [Inside HotSpot] Java分代堆

    [Inside HotSpot] Java分代堆 1. 宇宙初始化 JVM在启动的时候会初始化各种结构,比如模板解释器,类加载器,当然也包括这篇文章的主题,Java堆.在hotspot源码结构中gc/ ...

  6. [Inside HotSpot] 模板解释器

    0. 简介 众所周知,hotspot默认使用解释+编译混合(-Xmixed)的方式执行代码.它首先使用模板解释器对字节码进行解释,当发现一段代码是热点的时候,就使用C1/C2 JIT进行优化编译再执行 ...

  7. [Inside HotSpot] C1编译器工作流程及中间表示

    1. C1编译器线程 C1编译器(aka Client Compiler)的代码位于hotspot\share\c1.C1编译线程(C1 CompilerThread)会阻塞在任务队列,当发现队列有编 ...

  8. [Inside HotSpot] Java的方法调用

    1. 方法调用模块入口 Java所有的方法调用都会经过JavaCalls模块.该模块又细分为call_virtual调用虚函数,call_static调用静态函数等.虚函数调用会根据对象类型进行方法决 ...

  9. [Inside HotSpot] hotspot的启动流程与main方法调用

    hotspot的启动流程与main方法调用 虚拟机的使命就是执行public static void main(String[])方法,从虚拟机创建到main方法执行会经过一系列流程.这篇文章详细讨论 ...

随机推荐

  1. JAVA基础篇—String和StringBuffer

    区别: (1)String类对象为不可变对象,一旦你修改了String对象的值,隐性重新创建了一个新的对象,释放原String对象,StringBuffer类对象为可修改对象,可以通过append() ...

  2. 数学基础:HUD1124-Factorial(N!末尾0的个数)

    Factorial Problem Description The most important part of a GSM network is so called Base Transceiver ...

  3. Post页面爬取失败__编码问题

    python3爬取Post页面时, 报以下错误 "POST data should be bytes or an iterable of bytes. It cannot be of typ ...

  4. T-SQL中的indexof函数

    在C#字符串中查找字符有indexof方法,那么在T-SQL与之相对应的是CHARINDEX方法,其语法为CHARINDEX(要查找的字符,字符串),返回一个数字. CHARINDEX(',','aa ...

  5. VMware Workstation 14 PRO 下安装Ubuntu 16.04 LTS教程

    一.准备好安装的VMware Workstation 14 PRO 1.VMware Workstation 14 PRO下载链接:http://rj.baidu.com/soft/detail/13 ...

  6. Python学习-day7 类 部分socket

    这周还是继续关于类的学习,在面向对象的学习过程中又学习了网络编程,并且提交了编写FTP的作业. 复习一下类的相关概念和定义 类      属性           实例变量:内存中           ...

  7. IO Streams:格式化

    简介 实现格式化接口的流对象是PrintWriter,字符流类或PrintStream(字节流类). 注意:您可能唯一需要的PrintStream对象是System.out和System.err. ( ...

  8. HDU-3718 Similarity

    题目只有26个字母,所以我们新建一个二分图,v[i][j]表示字母i对应字母j时能成功匹配的个数,给这个边矩阵v求个最大匹配就是答案. #include <cstdlib> #includ ...

  9. 刷题总结——Tree2cycle(hdu4714 树形dp)

    题目: A tree with N nodes and N-1 edges is given. To connect or disconnect one edge, we need 1 unit of ...

  10. caffe编译新问题

    我在一台机子上,配置第二个caffe的时候,复制之前的Makefile文件,直接 make all 居然报错了报错如下 ndefined reference to cv::imread(cv::Str ...