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. python numpy复制array

    numpy快速复制array 前段时间想到一个算法,需要实现array的自我复制,直接上代码,两种复制方式, 整体复制 a=[[10,10,50,50],[10,10,40,50]] np.tile( ...

  2. python中字符串的一些用法

    一.字符串的拼接:      a=‘123’      b=‘abc’       d=‘hello world’ 1.print(a+b) 2.print(a,b) 3. c=‘ ’.join((a ...

  3. OpenCV中的绘图函数

    OpenCV可以用来绘制不同的集合图形,包括直线,矩形,圆,椭圆,多边形以及在图片上添加文字.用到的绘图函数包括 cv2.line(),cv2.circle(),cv2.rectangle() ,cv ...

  4. Applied Nonparametric Statistics-lec7

    Ref: https://onlinecourses.science.psu.edu/stat464/print/book/export/html/9 经过前面的步骤,我们已经可以判断几个样本之间是否 ...

  5. LeetCode(226)Invert Binary Tree

    题目 分析 交换二叉树的左右子树. 递归非递归两种方法实现. AC代码 class Solution { public: //递归实现 TreeNode* invertTree(TreeNode* r ...

  6. 排序 sort函数

    sort函数见下表: 函数名 功能描述 sort 对给定区间所有元素进行排序 stable_sort 对给定区间所有元素进行稳定排序 partial_sort 对给定区间所有元素部分排序 partia ...

  7. fortran子程序传入可变数组要在module里实现

    坑死我了,我说怎么子程序传递不了可变数组 在写fortran程序的时候,要对矩阵实现特定的功能,如高斯法解线性方程组,很多时候子程序不知道矩阵的大小,如有限元程序中先要用程序得到总体刚度矩阵再把总刚传 ...

  8. asp.net多线程在web页面中简单使用

    需求:一个web页面 default.aspx 里面有两个控件GridView1,GridView2,通过两个线程分别加载绑定数据. 绑定GridView1:void BindCategory()  ...

  9. 聊聊、Java 网络编程

    Socket 编程大家都不陌生,Java 学习中必学的部分,也是 Java网络编程核心内容之一.Java 网络编程又包括 TCP.UDP,URL 等模块.TCP 对应 Socket模块,UDP 对应  ...

  10. AtCoder Grand Contest 020

    A - Move and Win Time limit : 1sec / Memory limit : 512MB Score : 300 points Problem Statement A gam ...