关于不同GC策略下的GC日志的解读 SerialGC Par

这是我参与11月更文挑战的第12天,活动详情查看:2021最后一次更文挑战

昨天,我们介绍了GC日志,并且对并行GC进行GC日志的分析和解读,那我们就继续对不同GC策略都进行一个演示,来看看有什么不同,正好对专栏内提到的知识进行一个梳理和整合。

SerialGC

image.png

串行GC,历史最悠久的垃圾回收器,回收时会触发STW,我们看一下暂停时间是29ms,我们可以看到young区的大小 [DefNew: 279616K->34944K(314560K)压缩了大概248M,整个young区的大小大概是314M,我们整个的这个堆内存设置的是1G: 279616K>81630K(1013632K),那整个堆内存压缩之后是81M左右,那我们的Old区就是47M左右,和并行GC差不多,不过暂停时间比并行GC时间长,因为是单线程的,所以效率是比较低的。

ParallelGC

写过了,地址:juejin.cn/post/702992…

ConcurrentMarkSweepGC

我在专栏里提到过CMS垃圾回收器,它是和我们的这个ParNew一起使用的,因为后面G1GC就登场了,所以官方的意思是把它们两个全部取代。

我们可以看到young区[ParNew: 279616K->34944K(314560K), 0.0132556 secs],跟前面并行GC差不多,STW用了13毫秒。
image.png

Old区是用了CMS,然后是第一个阶段初始化标记:只标记我们的根对象和根对象可达的对象,所以速度是比较快的,就用了0.1毫秒,之后是并发标记、并发预清理阶段,中间还发生了几次youngGC,因为CMS主要是回收老年代的,所以中间会发生几次youngGC。
image.png

接下来,是进行并发的最终标记,然后并发清理,之后进行并发重置,等待下一次回收。
image.png

G1GC

可以看出G1GC的日志是非常之复杂,我一开始都看懵了,我们隐藏掉一些细节吧,
image.png

可以看出,我们的这个G1GC跟我们的这个CMSGC其实差不多,G1GC只是把我们这个java堆分成了很多的Region,我们可以看出当第一次这个分配大对象失败的时候,触发了我们的G1GC,关于G1GC,专栏里有写道:juejin.cn/post/699943… 不多提了。

image.png

总结

如果使用SerialGC,那垃圾收集就使用Serial+SerialOld的组合策略进行回收,由于是单线程的垃圾回收器,所以回收时占用的额外内存资源是所有垃圾回收器中占用最小的,而且在单核场景下,没有线程交互的开销,那对于桌面应用来说,无疑是一个比较好的选择,所以当虚拟机使用客户端模式下,默认的GC策略就是Serial。

如果使用ParallelGC,那垃圾收集器使用Parallel Scavenge+SerialOld的组合策略进行回收,如果说串行GC是单人干活,那并行GC就是多人干活,效率自然要高一些,并行GC的关注点是高吞吐量,但是它也有GC暂停的,可能时间会特别长,因此,也不适用于一些追求系统延迟的应用。

如果使用CmsGC,那垃圾收集器使用Parallel Scavenge+SerialOld的组合策略进行回收,
如果系统的关注点是减少回收的停顿时间,提高给用户的响应速度,那CMS是一个不错的选择,但CMS的缺点是无法处理浮动垃圾,而且对CPU的算力要求比较高。

如果使用G1GC,G1的设计目标是把垃圾收集的STW时间变成可控的,面向的是服务端的应用,适合大内存,低延迟的场景,但G1需要的CPU的算力远比CMS要高,而且G1的实现更为复杂,也会占用比CMS更多的内存空间。

注意

堆内存的设置其实是反映实际容纳对象的大小的,堆内存设置的越大,容纳的对象也越多,发生GC的次数也会少,但是会造成GC的暂停时间特别长,所以这个是我们需要权衡的一个点,反之亦然。

配置参数时,一定要把-Xmx -Xms设置成一样的,不然,会发生内存的抖动,不光发生了很多次的Full GC,还进行了扩容,得不偿失。

防止我们的GC退化,如果GC退化成Full GC,那对性能的影响是非常大的。

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%