资讯专栏INFORMATION COLUMN

CMS垃圾回收和线上Full GC排查

zr_hebo / 3534人阅读

摘要:是一款基于并发使用标记清除算法的垃圾回收算法,只针对老年代进行垃圾回收。收集器工作时,工作线程和用户线程可以并发执行,以达到降低时间的目的。并发清理清理垃圾对象,这个阶段线程和用户线程并发执行。

背景

我们上线Java服务的时候需要对其配置一些JVM参数,如堆空间大小、虚拟机栈大小、垃圾回收算法。对于年轻代和老年代我们可以配置不同的垃圾回收算法。在一些对rt要求很高的场景,服务不能有长时间的卡顿,CMS就可以运用于此场景。

Concurrent Mark Sweep,是一款基于并发、使用标记清除算法的垃圾回收算法,只针对老年代进行垃圾回收。CMS收集器工作时,GC工作线程和用户线程可以并发执行,以达到降低STW时间的目的。

开起VM选项-XX:+UseConcMarkSweepGC,表示对老年代的回收采用CMS。

前置知识 STW

首先,我们需要厘清一个概念,即只有标记阶段才需要STW。标记完成以后,需要清除的对象已经确定,无论此时是否产生新的垃圾,都不影响对这些对象的清理。也就是说,清除阶段是可以设计成和用户线程并发执行的。

JVM在暂停的时候,需要选准一个时机,由于JVM系统运行期间的复杂性,不可能做到随时暂停,因此引入了安全点(safepoint)的概念:程序只有在运行到安全点的时候,才可以暂停下来。HotSpot采用主动中断的方式,让执行线程在运行期轮询是否需要暂停的标志,若需要则中断挂起。HotSpot使用了几条短小精炼的汇编指令便可完成安全点轮询以及触发线程中断,因此对系统性能的影响几乎可以忽略不计。

可达性

可达性是指,如果一个对象会被至少一个程序中的可达对象通过直接或间接的方式引用,则称该对象是可达的。更详细地说,一个对象满足一下两个条件之一,即被判定为可达的。

1.本身是根对象。根(root)是指由堆以外空间访问的对象。JVM会将以下对象标记为根:a.虚拟机栈(栈帧中的本地变量表)中引用的对象;b.方法区中的类静态属性引用的对象;c.方法区中的常量引用的对象;d.本地方法栈中JNI的引用对象。

2.被一个可达的对象引用。

CMS的几个阶段

CMS将可达性分析分解成两个阶段:a.仅扫描与根节点直接关联的对象; b.继续向下扫描完所有对象。因此,标记阶段也被拆分成两个阶段,即初始标记并发标记

CMS完整的收集过程如下:

初始标记(init-mark):仅扫描与根节点直接关联的对象并标记,这个阶段必须STW, 由于跟节点数量有限,所以这个过程非常短暂。

并发标记(concurrent-marking):与用户线程并发标记。这个阶段在初始标记的基础上继续向下追溯标记。在并发标记阶段,用户线程和标记线程并发执行,所以用户不会感受到停顿。

并发预清理(concurrent-precleaning):与用户线程并发进行。在并发标记阶段一些对象的引用已经发生了变化,precleaning会发现这些引用关系的改变,并将存活的对象标记。举个例子:如果线程A有一个指向对象X的引用,并将该引用传递给了线程B,CMS需要记录下线程B持有了对象X,即使线程A已经不存在了。precleaning是为了减少下一阶段“重新标记”的工作量,因为remark阶段会STW

重新标记(remark) remark阶段会STW。如果应用正在并发运行且在不断地改变对象引用,CMS则不能准确地确定某个对象是否存活。所以CMS会在remark阶段STW,从而获取所有引用关系的改变。

并发清理(concurrent-sweeping):清理垃圾对象,这个阶段GC线程和用户线程并发执行。

并发重置(concurrent-reset):重置CMS收集器的数据结构,做好下一次执行GC任务的准备工作。

线上Full GC分析

线上某服务的老年代配置了CMS,但却在gc.log发现连续Full GC的问题。JVM参数配置如下:

-XX:+UseCMSInitiatingOccupancyOnly
-XX:CMSInitiatingOccupancyFraction=68

参数的意义是:在老年代到68%的时候,会触发一次CMS GC,应该是出现类似如下的日志:

T20:10:37.803+0800: 3246087.559: [CMS-concurrent-mark-start]
T20:10:38.463+0800: 3246088.220: [CMS-concurrent-mark: 0.661/0.661 secs] [Times: user=3.17 sys=0.56, real=0.66 secs]
T20:10:38.463+0800: 3246088.220: [CMS-concurrent-preclean-start]
T20:10:38.552+0800: 3246088.309: [CMS-concurrent-preclean: 0.069/0.089 secs] [Times: user=0.14 sys=0.04, real=0.09 secs]_
T20:10:38.552+0800: 3246088.309: [CMS-concurrent-abortable-preclean-start]

但线上环境的日志却出现如下的情况:

老年代配置了900M,但却在只使用了50+M的时候触发了Full GC,而且是在短暂的时间内连续触发。

配置了CMS却触发Full GC,有以下几种可能:

大对象分配时,年轻代不够,直接晋升到老年代,老年代空间也不够,触发 Full GC(老年代还剩800+M,显然不可能)

内存碎片导致(由于CMS是基于标记清除算法的,所有会导致内存碎片,但通过grep -i "cms" gc.log,JVM尚未触发过CMS回收,所以也不存在内存碎片的说法)

CMS GC失败导致(从gc.log并未找到concurrent mode failure的记录,排除)

jmap -histo(人为执行该命令)

经笔者回忆,在中午快12点的时候确实登录过线上机,执行过jmap -histo:live命令,经验证,手动执行jmap -histo:live,也确实会在gc.log出现触发 Full GC的现象,问题得到验证。

原文链接

https://segmentfault.com/a/11...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/69650.html

相关文章

  • 《深入理解java虚拟机》学习笔记系列——垃圾收集器&内存分配策略

    摘要:虚拟机所处的区域,则表示它是属于新生代收集器还是老年代收集器。虚拟机总共运行了分钟,其中垃圾收集花掉分钟,那么吞吐量就是。收集器线程所占用的数量为。 本文主要从GC(垃圾回收)的角度试着对jvm中的内存分配策略与相应的垃圾收集器做一个介绍。 注:还是老规矩,本着能画图就不BB原则,尽量将各知识点通过思维导图或者其他模型图的方式进行说明。文字仅记录额外的思考与心得,以及其他特殊情况 内存...

    calx 评论0 收藏0
  • [译]GC专家系列3-GC调优

    摘要:原文链接本篇是专家系列的第三篇。但是,请记住调优是不得已时的选择。缩短耗时的单次执行与相比,耗时有较明显的增加。创建文件过程中,进程会中断,因此不要在正常运行时系统上做此操作。因此校验结果并根据具体的服务需要,决定是否要进行调优。 原文链接:http://www.cubrid.org/blog/dev-platform/how-to-tune-java-garbage-collecti...

    leap_frog 评论0 收藏0
  • 记一次线上频繁FGC的事件和解决方式

    摘要:直接显示了一个疑似内存泄漏的问题。然后分析文件给出的信息,发现一个叫的类。文件里面说的内存泄漏的大概的意思就是说,这个类里面的存放的东西太多了,爆掉了。修改了代码将调用的地方改成了单例。修改完线上跑了一段日子,后来也没有出现过这样的问题。 问题描述:     早上去公司上班,突然就邮件一直报警,接口报异常,然后去查服务器的运行情况,发现java的cpu爆了.接着就开始排查问题 问题解决...

    Alliot 评论0 收藏0
  • 深入理解虚拟机之垃圾回收

    摘要:深入理解虚拟机高级特性与最佳实践第二版读书笔记与常见面试题总结上篇文章传送门深入理解虚拟机之内存区域本节常见面试题推荐带着问题阅读,问题答案在文中都有提到如何判断对象是否死亡两种方法。虚引用主要用来跟踪对象被垃圾回收的活动。 《深入理解Java虚拟机:JVM高级特性与最佳实践(第二版》读书笔记与常见面试题总结 上篇文章传送门: 深入理解虚拟机之Java内存区域 本节常见面试题(推荐带着...

    IamDLY 评论0 收藏0

发表评论

0条评论

zr_hebo

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<