文档章节

关于施用full gc频繁的分析及解决

DEC_LIU
 DEC_LIU
发布于 2013/10/13 20:32
字数 1926
阅读 12104
收藏 17
关于应用full gc频繁的分析及解决
很久前的工作日记了,移到ITeye上来。

现象

系统报警full gc次数过多,每2分钟达到了5~6次,这是不正常的现象
在full gc报警时的gc.log如下:
在full gc报警时的jstat如下:
sudo -u admin -H /opt/taobao/java/bin/jstat -gcutil `pgrep java` 2000 100
 
此时的cpu如下(基本都是在做gc): 
将应用重启后,问题解决
但是当后台执行低价航线更新时,过大概十几个小时后,又出现上述情况!

分析

当频繁full gc时,jstack打印出堆栈信息如下:
sudo -u admin -H /opt/taobao/java/bin/jstack `pgrep java` > #your file path#
可以看到的确是在跑低价信息
另外在应用频繁full gc时和应用正常时,也执行了如下2种命令:
sudo -u admin -H /opt/taobao/java/bin/jmap -histo `pgrep` > #your file path#
sudo -u admin -H /opt/taobao/java/bin/jmap -histo:live `pgrep` > #your file path#(live会产生full gc)
目的是确认以下2种信息:
(1)是否存在某些引用的不正常,造成对象始终可达而无法回收(Java中的内存泄漏)
(2)是否真是由于在频繁full gc时同时又有大量请求进入分配内存从而处理不过来,
        造成concurrent mode failure?
下图是在应用正常情况下,jmap不加live,产生的histo信息:
下图是在应用正常情况下,jmap加live,产生的histo信息:
下图是在应用频繁full gc情况下,jmap不加live和加live,产生的histo信息:
从上述几个图中可以看到:
(1)在应用正常情况下,图中标红的对象是被回收的,因此不是内存泄漏问题
(2)在应用频繁full gc时,标红的对象即使加live也是未被回收的,因上就是在频繁full gc时,
        同时又有大量请求进入分配内存从而处理不过来的问题

先从解决问题的角度,看怎样造成频繁的full gc?

从分析CMS GC开始
先给个CMS GC的概况:
(1)young gc
可以看到,当eden满时,young gc使用的是ParNew收集器
ParNew: 2230361K->129028K(2403008K), 0.2363650 secs解释:
1)2230361K->129028K,指回收前后eden+s1(或s2)大小
2)2403008K,指可用的young代的大小,即eden+s1(或s2)
3)0.2363650 secs,指消耗时间
2324774K->223451K(3975872K), 0.2366810 sec解释:
1)2335109K->140198K,指整个堆大小的变化
(heap=(young+old)+perm;young=eden+s1+s2;s1=s2=young/(survivor ratio+2))
2)0.2366810 sec,指消耗时间
[Times: user=0.60 sys=0.02, real=0.24 secs]解释:指用户时间,系统时间,真实时间
2cms gc
当使用CMS收集器时,当开始进行收集时,old代的收集过程如下所示:
a)首先jvm根据-XX:CMSInitiatingOccupancyFraction,-XX:+UseCMSInitiatingOccupancyOnly
     来决定什么时间开始垃圾收集
b)如果设置了-XX:+UseCMSInitiatingOccupancyOnly,那么只有当old代占用确实达到了
     -XX:CMSInitiatingOccupancyFraction参数所设定的比例时才会触发cms gc
c)如果没有设置-XX:+UseCMSInitiatingOccupancyOnly,那么系统会根据统计数据自行决定什么时候
    触发cms gc;因此有时会遇到设置了80%比例才cms gc,但是50%时就已经触发了,就是因为这个参数
    没有设置的原因
d)当cms gc开始时,首先的阶段是CMS-initial-mark,此阶段是初始标记阶段,是stop the world阶段,
     因此此阶段标记的对象只是从root集最直接可达的对象
CMS-initial-mark:961330K(1572864K),指标记时,old代的已用空间和总空间
e)下一个阶段是CMS-concurrent-mark,此阶段是和应用线程并发执行的,所谓并发收集器指的就是这个,
     主要作用是标记可达的对象
此阶段会打印2条日志:CMS-concurrent-mark-start,CMS-concurrent-mark
f)下一个阶段是CMS-concurrent-preclean,此阶段主要是进行一些预清理,因为标记和应用线程是并发执行的,
    因此会有些对象的状态在标记后会改变,此阶段正是解决这个问题
因为之后的Rescan阶段也会stop the world,为了使暂停的时间尽可能的小,也需要preclean阶段先做一部分
    工作以节省时间
此阶段会打印2条日志:CMS-concurrent-preclean-start,CMS-concurrent-preclean
g)下一阶段是CMS-concurrent-abortable-preclean阶段,加入此阶段的目的是使cms gc更加可控一些,
     作用也是执行一些预清理,以减少Rescan阶段造成应用暂停的时间
此阶段涉及几个参数:
-XX:CMSMaxAbortablePrecleanTime:当abortable-preclean阶段执行达到这个时间时才会结束
-XX:CMSScheduleRemarkEdenSizeThreshold(默认2m):控制abortable-preclean阶段什么时候开始执行,
即当eden使用达到此值时,才会开始abortable-preclean阶段
-XX:CMSScheduleRemarkEdenPenetratio(默认50%):控制abortable-preclean阶段什么时候结束执行
此阶段会打印一些日志如下:
CMS-concurrent-abortable-preclean-start,CMS-concurrent-abortable-preclean,
CMS:abort preclean due to time XXX
h)再下一个阶段是第二个stop the world阶段了,即Rescan阶段,此阶段暂停应用线程,对对象进行重新扫描并
     标记
YG occupancy:964861K(2403008K),指执行时young代的情况
CMS remark:961330K(1572864K),指执行时old代的情况
此外,还打印出了弱引用处理、类卸载等过程的耗时
i)再下一个阶段是CMS-concurrent-sweep,进行并发的垃圾清理
j)最后是CMS-concurrent-reset,为下一次cms gc重置相关数据结构
(3)full gc:
有2种情况会触发full gc,在full gc时,整个应用会暂停
a)concurrent-mode-failure:当cms gc正进行时,此时有新的对象要进行old代,但是old代空间不足造成的
b)promotion-failed:当进行young gc时,有部分young代对象仍然可用,但是S1或S2放不下,
    因此需要放到old代,但此时old代空间无法容纳此

 

频繁full gc的原因
从日志中可以看出有大量的concurrent-mode-failure,因此正是当cms gc进行时,有新的对象要进行old代,
但是old代空间不足造成的full gc
进程的jvm参数如下所示:
影响cms gc时长及触发的参数是以下2个:
-XX:CMSMaxAbortablePrecleanTime=5000
-XX:CMSInitiatingOccupancyFraction=80
解决也是针对这两个参数来的
根本的原因是每次请求消耗的内存量过大

解决

(1)针对cms gc的触发阶段,调整-XX:CMSInitiatingOccupancyFraction=50,提早触发cms gc,就可以
        缓解当old代达到80%,cms gc处理不完,从而造成concurrent mode failure引发full gc
(2)修改-XX:CMSMaxAbortablePrecleanTime=500,缩小CMS-concurrent-abortable-preclean阶段
        的时间
(3)考虑到cms gc时不会进行compact,因此加入-XX:+UseCMSCompactAtFullCollection
       (cms gc后会进行内存的compact)和-XX:CMSFullGCsBeforeCompaction=4
       (在full gc4次后会进行compact)参数
但是运行了一段时间后,只不过时间更长了,又会出现频繁full gc
计算了一下heap各个代的大小(可以用jmap -heap查看):
total heap=young+old=4096m
perm:256m
young=s1+s2+eden=2560m
young avail=eden+s1=2133.375+213.3125=2346.6875m
s1=2560/(10+1+1)=213.3125m
s2=s1
eden=2133.375m
old=1536m
可以看到eden大于old,在极端情况下(young区的所有对象全都要进入到old时,就会触发full gc),
因此在应用频繁full gc时,很有可能old代是不够用的,因此想到将old代加大,young代减小
改成以下:
-Xmn1920m
新的各代大小:
total heap=young+old=4096m
perm:256m
young=s1+s2+eden=1920m
young avail=eden+s1=2133.375+213.3125=1760m
s1=1760/(10+1+1)=160m
s2=s1
eden=1600m
old=2176m
此时的eden小于old,可以缓解一些问题
 
改完之后,运行了2天,问题解决,未频繁报full gc

本文转载自:

DEC_LIU
粉丝 27
博文 18
码字总数 9469
作品 0
浦东
架构师
私信 提问
加载中

评论(2)

天下无双黑猫先生
天下无双黑猫先生
学习下,层主目前的一个项目是定时导数据,状况是内存中byte类型的数据比较多,直接写进eden,GC完很快内存又被塞满,头大😷
程序猿Zz
大牛,请教个问题,sudo -u admin -H /opt/taobao/java/bin/jmap -histo `pgrep` > #your file path#这条命令中的`pgrep`表示什么,我本地运行报错
关于应用full gc频繁的分析及解决

关于应用full gc频繁的分析及解决 很久前的工作日记了,移到ITeye上来。 现象 系统报警full gc次数过多,每2分钟达到了5~6次,这是不正常的现象 在full gc报警时的gc.log如下: 在full gc报...

江江的喵
2015/12/16
110
0
再次剖析 “一个 JVM 参数引发的频繁 CMS GC”

再次剖析 “一个 JVM 参数引发的频繁 CMS GC” 简书 涤生。 转载请注明原创出处,谢谢! 如果读完觉得有收获的话,欢迎点赞加关注。 前言 前几天这篇《一个 JVM 参数引发的频繁 CMS GC》文章...

涤生_YinQi
04/10
0
0
详解JVM内存管理与垃圾回收机制2 - 何为垃圾

随着编程语言的发展,GC的功能不断增强,性能也不断提高,作为语言背后的无名英雄,GC离我们的工作似乎越来越远。作为Java程序员,对这一点也许会有更深的体会,我们不需要了解太多与GC相关的...

方志朋
2018/11/25
0
0
fullgc过于频繁该怎么解决?(问题8)

fullgc过于频繁有可能会造成oom,有可能不会。 首先明确一下,这篇文章的重点是分析后面一种情况,即应用在频繁的fullgc,但并没有出现oom。 我们来想一下为什么会出现fullgc,触发原因有很多...

北风男
2018/04/26
93
0
full gc 监控 分析

命令查看gc情况,以及jvm内存使用比例 如何发现是否发生FULL GC和FULL GC是否频繁 使用JDK自带的轻量级小工具jstat 语法结构: Usage: jstat -help -options jstat - [-t] [-h] [ []] FULL G...

johnli
2016/09/26
110
0

没有更多内容

加载失败,请刷新页面

加载更多

Spring Boot + Mybatis + Ehcache 二级缓存实例

二级缓存是多个SqlSession共享的,其作用域是mapper的同一个namespace,不同的sqlSession两次执行相同namespace下的sql语句且向sql中传递参数也相同即最终执行相同的sql语句,第一次执行完毕...

xiaolyuh
15分钟前
4
0
Spring源码学习(二)哎呦,按菜谱做菜与AbstractAutowireCapableBeanFactory.createBean流程差不多

记得跟老婆谈恋爱时,有一天心血来潮给老婆做饭,按照菜谱一步一步的做,结果差点把厨房烧了!!! 这事至今老婆还记得。 入口 上一篇说了,AbstractBeanFactory.getBean的主流程 ,今天来说下...

温安适
17分钟前
34
0
前端UI攻城狮 你们该抛弃jQuery了

你不再需要jQuery! Web工程师太依赖jQuery了,某种意义上说jQuery已经成了JavaScript的同义词。但是我们真的需要他么?或许我们应该反思一下什么时候才真的需要jQuery。 对我个人而言开始使...

前端老手
19分钟前
5
0
六、Java设计模式之工厂方法

工厂方法定义: 定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类,工厂方法让类的实例化推迟到子类中进行 类型:创建型 工厂方法-使用场景: 创建对象需要大量重复的代码 ...

东风破2019
今天
5
0
win服务器管理遇到的一系列问题记录

有些小伙伴在使用iis7远程桌面管理工具的时候总是会遇到一系列的问题,下面就是为大家介绍一下服务器日常管理过程中出现的问题及我的解决办法和心得。希望能帮到大家。   拒绝服务器重新启...

1717197346
今天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部