CMS gc调整实践(续)

2 篇文章 0 订阅

 

转载自 ---- http://www.blogjava.net/killme2008/archive/2009/09/22/296085.html

 

       在初步确定CMS参数后,系统运行了几天,今天尝试在线上打开了GC日志,按阿宝同学的说法是gc日志的开销比之jstat还小,打开之后发现确实影响很小。打开GC日志之后又发现几个隐藏的问题比较有价值,这里记录下。

   首先是系统在启动的时候有一次System.gc()调用引起的full gc,日志输出类似这样:

1.201 : [Full GC (System)  1.201 : [CMS: 0K -> 797K(1310720K),  0.1090540  secs] 29499K -> 797K(1546688K), [CMS Perm : 5550K -> 5547K(65536K)],  0.1091860  secs] [Times: user = 0.05  sys = 0.06 , real = 0.11  secs]

   可以确认的是我们系统里的代码绝对没有调用System.gc()方法,但是不保证第三方代码有调用,通过搜索代码引用,后来定位到了mina的ByteBuffer创建上面。Mina 1.1封装的ByteBuffer的allocate()方法默认创建的是Direct ByteBuffer ,而DirectByteBuffer的构造函数里调用了

Bits.reserveMemory(cap);


这个方法强制调用了System.gc():

static   void  reserveMemory( long  size) {

    
synchronized  (Bits. class ) {
        
if  ( ! memoryLimitSet  &&  VM.isBooted()) {
        maxMemory 
=  VM.maxDirectMemory();
        memoryLimitSet 
=   true ;
        }
        
if  (size  <=  maxMemory  -  reservedMemory) {
        reservedMemory 
+=  size;
        
return ;
        }
    }

    System.gc();
    
try  {
        Thread.sleep(
100 );
    } 
catch  (InterruptedException x) {
        
//  Restore interrupt status
        Thread.currentThread().interrupt();
    }
    
synchronized  (Bits. class ) {
        
if  (reservedMemory  +  size  >  maxMemory)
        
throw   new  OutOfMemoryError( " Direct buffer memory " );
        reservedMemory 
+=  size;
    }

    }

    调用这个方法是为了用户对Direct ByteBuffer的内存可控。而在我们系统中使用的通讯层初始化Decoder的时候通过Mina 1.1创建了一个Direct ByteBuffer,导致了这一次强制的full gc。这个Buffer因为是长期持有的,因此创建Direct类型也还可以接受。

    但是在这次GC后,又发现每隔一个小时就有一次System.gc()引起的full gc,这就太难以忍受了,日志大概是这样,注意间隔时间都是3600秒左右:

10570.672 : [Full GC (System)  10570.672 : [CMS: 779199K -> 107679K(1310720K),  1.2957430  secs] 872163K -> 107679K(1546688K), [CMS Perm : 23993K -> 15595K(65536K)],  1.2959630  secs] [Times: user = 1.27  sys = 0.02 , real = 1.30  secs] 
14171.971 : [Full GC (System)  14171.971 : [CMS: 680799K -> 83681K(1310720K),  1.0171580  secs] 836740K -> 83681K(1546688K), [CMS Perm : 20215K -> 15599K(65536K)],  1.0173850  secs] [Times: user = 0.97  sys = 0.01 , real = 1.02  secs] 
17774.020 : [Full GC (System)  17774.020 : [CMS: 676201K -> 79331K(1310720K),  0.9652670  secs] 817596K -> 79331K(1546688K), [CMS Perm : 22808K -> 15619K(65536K)],  0.9655150  secs] [Times: user = 0.93  sys = 0.02 , real = 0.97  secs] 
21374.989 : [Full GC (System)  21374.989 : [CMS: 677818K -> 78590K(1310720K),  0.9297080  secs] 822317K -> 78590K(1546688K), [CMS Perm : 16435K -> 15593K(65536K)],  0.9299620  secs] [Times: user = 0.89  sys = 0.01 , real = 0.93  secs] 
24976.948 : [Full GC (System)  24976.948 : [CMS: 659511K -> 77608K(1310720K),  0.9255360  secs] 794004K -> 77608K(1546688K), [CMS Perm : 22359K -> 15594K(65536K)],  0.9257760  secs] [Times: user = 0.88  sys = 0.02 , real = 0.93  secs] 
28578.892 : [Full GC (System)  28578.892 : [CMS: 562058K -> 77572K(1310720K),  0.8365500  secs] 735072K -> 77572K(1546688K), [CMS Perm : 15840K -> 15610K(65536K)],  0.8367990  secs] [Times: user = 0.82  sys = 0.00 , real = 0.84  secs] 
32179.731 : [Full GC (System)  32179.732 : [CMS: 549874K -> 77224K(1310720K),  0.7864400  secs] 561803K -> 77224K(1546688K), [CMS Perm : 16016K -> 15597K(65536K)],  0.7866540  secs] [Times: user = 0.75  sys = 0.01 , real = 0.79  secs]


    搜遍了源码和依赖库,没有再发现显式的gc调用,问题只能出在运行时上,突然想起我们的系统使用RMI暴露JMX给监控程序,监控程序通过RMI连接JMX监控系统和告警等,会不会是RMI的分布式垃圾收集 导致的?果然,一查资料,RMI的分布式收集会强制调用System.gc()来进行分布式GC,server端的间隔恰好是一个小时,这个参数可以通过:

- Dsun.rmi.dgc.server.gcInterval = 3600000

来调整。调长时间是一个解决办法,但是我们更希望能不出现显式的GC调用,禁止显式GC调用通过-XX:+DisableExplicitGC 是一个办法,但是禁止了分布式GC会导致什么问题却是心理没底,毕竟我们的JMX调用还是很频繁的,幸运的是JDK6还提供了另一个选项 -XX:+ExplicitGCInvokesConcurrent ,允许System.gc()也并发运行,调整DGC时间间隔加上这个选项双管齐下彻底解决了full gc的隐患。

    打开GC日志后发现的另一个问题是remark的时间过长,已经启用了并行remark,但是时间还是经常超过200毫秒,这个可能的原因有两个:我们的 年老代太大或者触发CMS的阀值太高了,CMS进行的时候年老代里的对象已经太多。初步的计划是调小-XX:SurvivorRatio增大救助空间并且 降低-XX:CMSInitiatingOccupancyFraction这个阀值。此外,还找到另一个可选参数-XX:+CMSScavengeBeforeRemark ,启用这个选项后,强制remark之前开始一次minor gc,减少remark的暂停时间,但是在remark之后也将立即开始又一次相对较长时间minor gc,如果你的minor gc很快的话可以考虑下这个选项,暂未实验。

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值