JVM默认老年代回收是 PSMarkSweep(Serial-Old) 还是Parallel Old? - 知乎
-XX:+UseG1GC -XX:+PrintGCTimeStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCDetails -Xloggc:gc.log -Dfile.encoding=gbk
java -jar -XX:+UseG1GC -XX:+PrintGCTimeStamps -XX:+PrintGCDateStamps -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCDetails -Xloggc:gc.log springbootDemo12_0.jar
2023-05-11T14:06:48.090+0800: 9.205: Total time for which application threads were stopped: 0.0001890 seconds, Stopping threads took: 0.0001305 seconds
2023-05-11T14:06:48.090+0800: 9.205: Total time for which application threads were stopped: 0.0001991 seconds, Stopping threads took: 0.0001356 seconds
2023-05-11T14:06:48.100+0800: 9.215: [GC concurrent-root-region-scan-end, 0.0232713 secs]
2023-05-11T14:06:48.100+0800: 9.215: [GC concurrent-mark-start]
2023-05-11T14:06:48.107+0800: 9.221: [GC concurrent-mark-end, 0.0065505 secs]
2023-05-11T14:06:48.107+0800: 9.222: [GC remark 2023-05-11T14:06:48.107+0800: 9.222: [Finalize Marking, 0.0084455 secs] 2023-05-11T14:06:48.116+0800: 9.231: [GC ref-proc, 0.0025846 secs] 2023-05-11T14:06:48.118+0800: 9.233: [Unloading, 0.0143943 secs], 0.0348725 secs]
[Times: user=1.98 sys=0.06, real=0.04 secs]
2023-05-11T14:06:48.142+0800: 9.257: Total time for which application threads were stopped: 0.0354685 seconds, Stopping threads took: 0.0001558 seconds
2023-05-11T14:06:48.143+0800: 9.257: [GC cleanup 30M->30M(2048M), 0.0261924 secs]
[Times: user=0.27 sys=0.02, real=0.03 secs]
-XX:+PrintGCTimeStamps:
(虚拟机启动以来的时间),如2.639、3.280等
2.639: Total time for which application threads were stopped: 0.0006871 seconds, Stopping threads took: 0.0003649 seconds
3.280: Total time for which application threads were stopped: 0.0007132 seconds, Stopping threads took: 0.0001169 seconds
3.318: Total time for which application threads were stopped: 0.0007101 seconds, Stopping threads took: 0.0001088 seconds
-XX:+PrintGCDateStamps
(详细时间戳)
-XX:+PrintGCDetails
(打印详细信息,新生代和老年代包括元空间都有(jdk1.8))
-verbose:gc
(或者-XX:+PrintGC),注意:不要有任何空格
G1作为JDK9+的默认GC.
JDK 1.8 默认使用 UseParallelGC 垃圾回收器,即 UseParallelGC is "Parallel Scavenge" + "Serial Old"
新生代(Parallel Scavenge),老年代(Ps MarkSweep)组合。
- UseParallelGC is "Parallel Scavenge" + "Serial Old"
- UseParallelOldGC is "Parallel Scavenge" + "Parallel Old"
64bit默认启动-server,-server下默认是PS回收框架组合,而PS回收框架下的两个参数,-XX:+UseParallelGC和-XX:+UseParallelOldGC默认都是指向并行收集器的,这是不是就说明,在默认情况前jvm启动的老年代收集器,就是ParallelOld??
以下是R大 RednaxelaFX 答案的节选,请移步答案区,非常感谢R大的解释。
“在这个改变之前,即便选择了ParallelGC,默认情况下ParallelOldGC并不会随即开启,而是要自己通过 -XX:+UseParallelOldGC 去选定。
在GC日志里,如果看到Full GC里有"ParOldGen"就是选择了ParallelOldGC。“
在这个改变之前,即便选择了ParallelGC,默认情况下ParallelOldGC并不会随即开启,而是要自己通过 -XX:+UseParallelOldGC 去选定。在GC日志里,如果看到Full GC里有"ParOldGen"就是选择了ParallelOldGC。
1、64bit的机器默认是-server生效的,且会忽略-client参数。
在虚拟机参数中添加 -XX:+PrintGCDetails -XX:+PrintCommandLineFlags参数,可以查看,默认的新生代垃圾收集器是ParallelGC,老年代的收集器ParOldGen.
-XX:+UseSerialGC参数可以指定使用新生代串行收集器和老年代串行收集器。
在Client模式下运行时,默认是串行收集器。
新生代串行收集器是使用复制算法;老年代串行处理器使用标记压缩算法。
-XX:+UseSerialGC:新生代、老年代都使用串行处理器。
-XX:+UseParNewGC:新生代使用ParNew回收器,老年代使用串行处理器。
-XX:+UseParallelGC:新生代使用ParallelGC回收器,老年代使用串行处理器。
-XX:+UseParallelGC 新生代使用ParallelGC回收器,老年代使用串行处理器
-XX:+UseParallelOldGC 新生代使用ParallelGC回收器,老年代使用ParallelOldGC回收器。
-XX:+UseConcMarkSweepGC启用CMS回收器
实例:
1新生代串行收集器:
0.834[GC 0.834:[DefNew:1111k->xxxxxxxxx] ]
2 新生代ParNew处理器
0.834[GC 0.834:[ParNew:1111k->xxxxxxxxx] ]
3、老年代串行
0.834[Full GC 0.834:[Tenured:1111k->xxxxxxxxx] ]
4、新生代ParallelGC
0.880:[GC [PSYoungGen:16448k->xxxx]]
5、老年代ParallelOldGC回收器
1.500:[Full GC[PSYoungGen:2533k->xxxxxxxxxxxxxxxx]]
6、老年代CMS
1.313 :[GC [1 CMS-initial-mark:69112k ]]
一、新生代ParNew回收器
ParNew使用
ParNew回收器是一个新生代工作的回收器,
-XX:+UseParNewGC:新生代使用ParNew回收器,老年代使用串行处理器。
-XX:+UseConcMarkSweepGC:新生代使用ParNew回收器,老年代使用CMS。
ParNew回收器工作时的线程数量可以使用-XX:ParallelGCThreads参数指定,一般线程数为cpu数。默认情况下,cpu<8时,ParallelGCThreads的值为cpu数量,如果大于8,值为3+((5*CPU_Count)/8),ParNew回收器日志为:
0.834[GC 0.834:[ParNew:1111k->xxxxxxxxx] ]
二、新生代ParallelGC回收器
新生代ParallelGC回收器也适用复制算法收集器,都是多线程、独占式的收集器,但它非常关注系统的吞吐量。
-XX:+UseParallelGC 新生代使用ParallelGC回收器,老年代使用串行处理器
ParallelGC回收器提供了两个重要的参数用于控制系统的吞吐量。
-XX:MaxGCPauseMillis:设置最大垃圾收集停顿时间,它的值是一个大于0的整数,会调整java堆大小伙子其他一些参数,尽可能把停顿时间控制在MaxGCPauseMillis以内。如设置该值很小,则虚拟机会使用一个较小的堆,便于垃圾回收,使回收时间短,但会带来垃圾回收频繁的问题,增加了垃圾回收总时间,降低了吞吐量。
-XX:GCTimeRatio:设置吞吐量大小。值在0~100之间的整数,如值为n,则会花费1/(1+n)的时间用于垃圾收集。如果把此参数设置为19,那允许的最大GC时间就占总时间的5%(即1/(1+19)),默认值为99,就是允许最大1%(即1/(1+99))的垃圾收集时间。
ParalletGC支持自适应,即设置
-XX:+UseAdaptiveSizePolicy可以打开自适应GC策略,每次都会重新计算新生代大小, Eden、survivor的比例,晋升老年代的对象年龄等参数都会被自动调整。以达到堆大小,吞吐量和停顿时间的平衡。在手工调优比较困难,可以直接指定这种自适应的方式,仅需指定堆的最大值,目标吞吐量(GCTimeRatio)和停顿时间(MaxGCPPauseMills),让虚拟机完成调优工作。
0.880:[GC [PSYoungGen:16448k->xxxx]]
JDK 1.8 默认使用 UseParallelGC 垃圾回收器,该垃圾回收器默认启动了 AdaptiveSizePolicy。
三、老年代ParallelOldGC回收器
老年代ParallelOldGC回收器也是一种多线程并发的收集器,和新生代ParallelGC回收器一样,也很关注系统吞吐量的收集器。
它从JDK1.6中才可以使用。
参数-XX:ParallelGCThreads也可以设置垃圾回收时的线程数量。
三、CMS回收器
CMS回收器主要关注于系统的停顿时间,是Concurrent Mark Sweep的缩写,意为并发标记清除,使用标记清除算法,同时也是一个使用多线程并行回收的垃圾收集器。
CMS工作时主要步骤有初始标记、并发标记、预清理、重新标记、并发清除和并发重置。其中初始标记和重新标记是独占系统资源的,而预清理、并发标记、并发清除和并发重置是可以和用户线程一起执行的。因此它可以在应用程序运行过程中进行垃圾回收。
根据标记清除算法,初始标记、并发标记和重新标记都是为了标记出需要回收的对象。并发清理则是在标记完成后,正是回收垃圾对象。并发重置是指在垃圾回收完成后,重新初始化CMS数据结构和数据,为下一次垃圾回收做好准备。
在整个CMS回收过程中,默认情况下,在并发标记之后,会有一个预清理的操作(也可以设置参数
-XX:CMSPrecleaningEnabled,不进行预清理
)。预清理是并发的,除了为正式清理做准备和检查以外,预清理还会尝试控制一次停顿时间。由于重新标记是独占CPU的,如果新生代GC发生后立即触发一次重新标记,那么一次停顿时间可能很长。为了避免这种情况,预清理时,会可以等待一次新生代GC的发生,然后根据历史性能数据预测一下新生代GC可能发生的时间,然后在当前时间和预测时间的中间时刻,进行重新标记。这样,最大程度上避免新生代GC和重新标记重合,尽可能减少一次停顿时间。
CMS默认启动的并发线程数是(ParallelGCThreads+3)/4,ParallelGCThreads表示GC并发时使用的线程数量,如果使用
当有4个并行线程时,有1个并发线程;
当有5~8个并行线程时,有2个并发线程。
可以通过-XX:ConcGCThreads或者-XX:ParallelCMSThreads来指定。当CPU资源比较紧张时,受到CMS回收器线程的影响,应用系统的性能在垃圾回收阶段可能会非常糟糕。
-XX:CMSInitiatingOccupancyFraction:默认是68
即老年代空间的使用率达到68%时,会执行一次CMS回收。如果应用程序的内存使用率增长过快,在CMS的执行过程中,已经出现了内存不足的情况,此时CMS回收就会失败,虚拟机将启动串行收集器进行垃圾回收。如果这样,应用程序将完全中断,直到垃圾回收完成,这样应用程序的停顿时间可能会较长。
根据应用特点,可以对该值进行调优,如果内存增长缓慢,则可以设置一个稍大的值,大的阈值可以有效降低CMS的触发频率,减少年老代回收的次数可以较为明显地改善应用程序性能。
反之,如果应用程序内存使用率增长很快,则应该降低这个阈值,以避免频繁触发年老代串行收集器。
缺点有空间碎片。
CMS碎片整理
-XX:+UseCMSCompactAtFullCollection:在CMS垃圾收集后,进行一次内存碎片整理。
-XX:CMSFullGCsBeforeCompaction:在进行多少次CMS回收后,进行一次内存压缩。
日志:
1.313 :[GC [1 CMS-initial-mark:69112k ]]
有关Class的回收
如果希望CMS回收Perm区,则需要打开-XX:+CMSClassUnloadingEnabled开关。如果条件允许,如果条件允许,那么系统会使用CMS的机制回收Perm区的Class数据。