物理内存耗尽、CMS GC碎片造成RT慢的两个Case

最近碰到的两个Case:一个是一个应用每天晚上集群里都有几台java进程退出的case;另一个是一个应用运行一段时间后在某种情况下RT突然变慢的Case,来看看排查过程。

Case I
第一个Case是每晚都有几台java进程退出,上机器看,dmesg | grep kill后发现是由于oom,所以os层面把进程给杀掉了,看了下当时的内存使用状况,发现物理内存快被用光了,说明这是一个堆外内存被用光的case,根据这个应用的特征,知道这个应用会用到大量的Direct Memory,看了下应用的启动参数,是没有配置MaxDirectMemorySize的,因此MaxDirectMemorySize的大小即等于-Xmx,从启动参数来看,-Xmx + MaxDirectMemorySize确实超过了物理内存的大小。

为什么会出现Direct Memory造成物理内存被耗光,就得说下Direct Memory的回收机制,Direct Memory是受GC控制的,例如ByteBuffer bb = ByteBuffer.allocateDirect(1024),这段代码的执行会在堆外占用1k的内存,Java堆内只会占用一个对象的指针引用的大小,堆外的这1k的空间只有当bb对象被回收时,才会被回收,这里会发现一个明显的不对称现象,就是堆外可能占用了很多,而堆内没占用多少,导致还没触发GC,那就很容易出现Direct Memory造成物理内存耗光。

为什么会有部分机器出现退出,而有些机器正常,按照上面的推测,主要就取决于有没有触发GC,从而回收堆外的Direct Memory,查看了正常的机器的gc log,确实触发了cms gc,而出问题的这些机器,则没有执行,这样就可以解释通了。

按照这样的分析,解决方法也就自然产生了,就是加上-XX:MaxDirectMemorySize,加上这个大小限制后,那么只要Direct Memory使用到达了这个大小,就会强制触发GC,这个大小如果设置的不够用,那么在日志中会看到java.lang.OutOfMemoryError: Direct buffer memory。

对于使用Direct Memory较多的场景,需要注意下MaxDirectMemorySize的设置,避免-Xmx + Direct Memory超出物理内存大小的现象。

Case II
有一个应用出现了非常奇怪的现象,就是运行了一段时间后会突然的出现rt从之前的50ms变成150ms左右的现象,但这个应用依赖的所有的后端的rt没什么变化,也就是应用的本身,但只要重启下应用就会恢复。

重启后就会恢复,因此决定用btrace一步一步跟,看看是哪里变慢了,但业务逻辑太复杂了,btrace不是很好跟,因此折腾了很久还是没看出太多的端倪。

业务方自己发现有个现象,就是在rt变慢的时候,gc的时间也会慢很多,在rt快的时候,ygc大概只需要15ms,而在rt变慢后,ygc大概需要45ms。

在采用cms gc的情况下,ygc变慢的原因通常是由于old gen出现了大量的碎片,因此猜测是这个问题,于是用jmap -histo:live强制执行了下full gc,执行完毕后,rt果然又从150ms降到了50ms。

因为是cms gc碎片问题造成的rt变慢,要解决还真的比较棘手,暂时只能是折腾成每天凌晨定时强制执行下full gc,悲催的碎片问题(所以还是那句话,如果不是因为heap size大,以及对rt比较敏感的话,能不用cms gc还是别用为妙)…

之前也碰过很多次cms gc的碎片问题,但通常是其造成的full gc导致的影响,而像这次case中这种对rt产生如此大影响的还真是第一次碰到(而且还有个诡异的现象,就是其实那些rt慢的机器在之前也有由于concurrent mode failure执行过full gc,但rt却没下降)。

—————————————————-
微信公众账号后台开放了之前青龙老贼透露的数据统计的功能,例如订阅公众账号的用户的增长状况、性别比例、省份比例,每篇文章的浏览、打开、原文链接和转发次数等,挺帅的。

我的这个账号的一些有趣的数字:
订阅者中MM的比例:5.81% (果然低呀)
订阅者中杭州用户的比例:31.92%(这样看来订阅者中阿里的不少)
文章的打开率: 50%左右… (真心不怎么高)

=============================
题图来源于:http://img.ifeng.com/tres/auto/9/2010/0531/107_4915254228_20100531165840.jpg
欢迎关注微信公众号:hellojavacases

关于此微信号:
分享Java问题排查的Case、Java业界的动态和新技术、Java的一些小知识点Test,以及和大家一起讨论一些Java问题或场景,这里只有Java细节的分享,没有大道理、大架构和大框架。

公众号上发布的消息都存放在http://hellojava.info上。

《物理内存耗尽、CMS GC碎片造成RT慢的两个Case》有3个想法

  1. ygc变慢的原因通常是由于old gen出现了大量的碎片.这二个是什么因果关系 ?为什么old gen有碎片,会导致ygc变慢 ?

发表评论

电子邮件地址不会被公开。 必填项已用*标注


*