full gc频繁的分析及解决案例

full gc频繁的分析及解决案例
2016-04-14 09:20:54      0个评论    来源:end‘s coding life  
收藏   我要投稿

现象

?


1

系统报警full gc次数过多,每2分钟达到了56次,这是不正常的现象

?


1

在full gc报警时的gc.log如下:

?


1

?


1

在full gc报警时的jstat如下:

?


1

sudo -u admin -H /opt/taobao/java/bin/jstat -gcutil `pgrep java` 2000 100

?


1

?


1

此时的cpu如下(基本都是在做gc):

?


1

?


1

将应用重启后,问题解决

?


1

但是当后台执行低价航线更新时,过大概十几个小时后,又出现上述情况!

分析

?


1

当频繁full gc时,jstack打印出堆栈信息如下:

?


1

sudo -u admin -H /opt/taobao/java/bin/jstack `pgrep java` > #your file path#

?


1

?


1

可以看到的确是在跑低价信息

?


1

另外在应用频繁full gc时和应用正常时,也执行了如下2种命令:

?


1

sudo -u admin -H /opt/taobao/java/bin/jmap -histo `pgrep` > #your file path#

?


1

sudo -u admin -H /opt/taobao/java/bin/jmap -histo:live `pgrep` > #your file path#(live会产生full gc)

?


1

目的是确认以下2种信息:

?


1

1)是否存在某些引用的不正常,造成对象始终可达而无法回收(Java中的内存泄漏)

?


1

2

2)是否真是由于在频繁full gc时同时又有大量请求进入分配内存从而处理不过来,

        造成concurrent mode failure?

?


1

下图是在应用正常情况下,jmap不加live,产生的histo信息:

?


1

?


1

下图是在应用正常情况下,jmap加live,产生的histo信息:

?


1

?


1

下图是在应用频繁full gc情况下,jmap不加live和加live,产生的histo信息:

?


1

?


1

从上述几个图中可以看到:

?


1

1)在应用正常情况下,图中标红的对象是被回收的,因此不是内存泄漏问题

?


1

2

2)在应用频繁full gc时,标红的对象即使加live也是未被回收的,因上就是在频繁full gc时,

        同时又有大量请求进入分配内存从而处理不过来的问题

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

从分析CMS GC开始

?


1

先给个CMS GC的概况:

?


1

1)young gc

?


1

可以看到,当eden满时,young gc使用的是ParNew收集器

?


1

ParNew: 2230361K->129028K(2403008K), 0.2363650 secs解释:

?


1

1)2230361K->129028K,指回收前后eden+s1(或s2)大小

?


1

2)2403008K,指可用的young代的大小,即eden+s1(或s2)

?


1

30.2363650 secs,指消耗时间

?


1

2324774K->223451K(3975872K), 0.2366810 sec解释:

?


1

2

1)2335109K->140198K,指整个堆大小的变化

(heap=(young+old)+perm;young=eden+s1+s2;s1=s2=young/(survivor ratio+2))

?


1

20.2366810 sec,指消耗时间

?


1

[Times: user=0.60 sys=0.02, real=0.24 secs]解释:指用户时间,系统时间,真实时间

?


1

?


1

2)cms gc

?


1

当使用CMS收集器时,当开始进行收集时,old代的收集过程如下所示:

?


1

2

a)首先jvm根据-XX:CMSInitiatingOccupancyFraction,-XX:+UseCMSInitiatingOccupancyOnly

     来决定什么时间开始垃圾收集

?


1

2

b)如果设置了-XX:+UseCMSInitiatingOccupancyOnly,那么只有当old代占用确实达到了

     -XX:CMSInitiatingOccupancyFraction参数所设定的比例时才会触发cms gc

?


1

2

3

c)如果没有设置-XX:+UseCMSInitiatingOccupancyOnly,那么系统会根据统计数据自行决定什么时候

    触发cms gc;因此有时会遇到设置了80%比例才cms gc,但是50%时就已经触发了,就是因为这个参数

    没有设置的原因

?


1

2

d)当cms gc开始时,首先的阶段是CMS-initial-mark,此阶段是初始标记阶段,是stop the world阶段,

     因此此阶段标记的对象只是从root集最直接可达的对象

?


1

CMS-initial-mark:961330K(1572864K),指标记时,old代的已用空间和总空间

?


1

2

e)下一个阶段是CMS-concurrent-mark,此阶段是和应用线程并发执行的,所谓并发收集器指的就是这个,

     主要作用是标记可达的对象

?


1

此阶段会打印2条日志:CMS-concurrent-mark-start,CMS-concurrent-mark

?


1

2

f)下一个阶段是CMS-concurrent-preclean,此阶段主要是进行一些预清理,因为标记和应用线程是并发执行的,

    因此会有些对象的状态在标记后会改变,此阶段正是解决这个问题

?


1

2

因为之后的Rescan阶段也会stop the world,为了使暂停的时间尽可能的小,也需要preclean阶段先做一部分

    工作以节省时间

?


1

此阶段会打印2条日志:CMS-concurrent-preclean-start,CMS-concurrent-preclean

?


1

2

g)下一阶段是CMS-concurrent-abortable-preclean阶段,加入此阶段的目的是使cms gc更加可控一些,

     作用也是执行一些预清理,以减少Rescan阶段造成应用暂停的时间

?


1

此阶段涉及几个参数:

?


1

-XX:CMSMaxAbortablePrecleanTime:当abortable-preclean阶段执行达到这个时间时才会结束

?


1

2

-XX:CMSScheduleRemarkEdenSizeThreshold(默认2m):控制abortable-preclean阶段什么时候开始执行,

即当eden使用达到此值时,才会开始abortable-preclean阶段

?


1

-XX:CMSScheduleRemarkEdenPenetratio(默认50%):控制abortable-preclean阶段什么时候结束执行

?


1

此阶段会打印一些日志如下:

?


1

2

CMS-concurrent-abortable-preclean-start,CMS-concurrent-abortable-preclean,

CMS:abort preclean due to time XXX

?


1

2

h)再下一个阶段是第二个stop the world阶段了,即Rescan阶段,此阶段暂停应用线程,对对象进行重新扫描并

     标记

?


1

YG occupancy:964861K(2403008K),指执行时young代的情况

?


1

CMS remark:961330K(1572864K),指执行时old代的情况

?


1

此外,还打印出了弱引用处理、类卸载等过程的耗时

?


1

i)再下一个阶段是CMS-concurrent-sweep,进行并发的垃圾清理

?


1

j)最后是CMS-concurrent-reset,为下一次cms gc重置相关数据结构

?


1

?


1

3)full gc:

?


1

2种情况会触发full gc,在full gc时,整个应用会暂停

?


1

a)concurrent-mode-failure:当cms gc正进行时,此时有新的对象要进行old代,但是old代空间不足造成的

?


1

2

b)promotion-failed:当进行young gc时,有部分young代对象仍然可用,但是S1或S2放不下,

    因此需要放到old代,但此时old代空间无法容纳此

?


1

频繁full gc的原因

?


1

2

从日志中可以看出有大量的concurrent-mode-failure,因此正是当cms gc进行时,有新的对象要进行old代,

但是old代空间不足造成的full gc

?


1

进程的jvm参数如下所示:

?


1

?


1

影响cms gc时长及触发的参数是以下2个:

?


1

-XX:CMSMaxAbortablePrecleanTime=5000

?


1

-XX:CMSInitiatingOccupancyFraction=80

?


1

解决也是针对这两个参数来的

?


1

根本的原因是每次请求消耗的内存量过大

解决

?


1

2

1)针对cms gc的触发阶段,调整-XX:CMSInitiatingOccupancyFraction=50,提早触发cms gc,就可以

        缓解当old代达到80%,cms gc处理不完,从而造成concurrent mode failure引发full gc

?


1

2

2)修改-XX:CMSMaxAbortablePrecleanTime=500,缩小CMS-concurrent-abortable-preclean阶段

        的时间

?


1

2

3

3)考虑到cms gc时不会进行compact,因此加入-XX:+UseCMSCompactAtFullCollection

       (cms gc后会进行内存的compact)和-XX:CMSFullGCsBeforeCompaction=4

       (在full gc4次后会进行compact)参数

?


1

但是运行了一段时间后,只不过时间更长了,又会出现频繁full gc

?


1

计算了一下heap各个代的大小(可以用jmap -heap查看):

?


1

total heap=young+old=4096m

?


1

perm:256m

?


1

young=s1+s2+eden=2560m

?


1

young avail=eden+s1=2133.375+213.3125=2346.6875m

?


1

s1=2560/(10+1+1)=213.3125m

?


1

s2=s1

?


1

eden=2133.375m

?


1

old=1536m

?


1

2

可以看到eden大于old,在极端情况下(young区的所有对象全都要进入到old时,就会触发full gc),

因此在应用频繁full gc时,很有可能old代是不够用的,因此想到将old代加大,young代减小

?


1

改成以下:

?


1

-Xmn1920m

?


1

新的各代大小:

?


1

total heap=young+old=4096m

?


1

perm:256m

?


1

young=s1+s2+eden=1920m

?


1

young avail=eden+s1=2133.375+213.3125=1760m

?


1

s1=1760/(10+1+1)=160m

?


1

s2=s1

?


1

eden=1600m

?


1

old=2176m

?


1

此时的eden小于old,可以缓解一些问题

?


1

?


1

改完之后,运行了2天,问题解决,未频繁报full gc

原文地址:https://www.cnblogs.com/lupeng2010/p/8252970.html

时间: 2024-10-18 12:21:35

full gc频繁的分析及解决案例的相关文章

TCP粘包问题分析和解决(全)

TCP通信粘包问题分析和解决(全) 在socket网络程序中,TCP和UDP分别是面向连接和非面向连接的.因此TCP的socket编程,收发两端(客户端和服务器端)都要有成对的socket,因此,发送端为了将多个发往接收端的包,更有效的发到对方,使用了优化方法(Nagle算法),将多次间隔较小.数据量小的数据,合并成一个大的数据块,然后进行封包.这样,接收端,就难于分辨出来了,必须提供科学的拆包机制. 对于UDP,不会使用块的合并优化算法,这样,实际上目前认为,是由于UDP支持的是一对多的模式,

c/c++服务器程序内存泄露问题分析及解决

由 www.169it.com 搜集整理 对于一个c/c++程序员来说,内存泄漏是一个常见的也是令人头疼的问题.已经有许多技术被研究出来以应对这个问题,比如 Smart Pointer,Garbage Collection等.Smart Pointer技术比较成熟,STL中已经包含支持Smart Pointer的class,但是它的使用似乎并不广泛,而且它也不能解决所有的问题:Garbage Collection技术在Java中已经比较成熟,但是在c/c++领域的发展并不顺畅,虽然很早就有人思考

分析和解决mnesia过载问题

mnesia在频繁操作数据的过程可能会报错:** WARNING ** Mnesia is overloaded: {dump_log, write_threshold},可以看出,mnesia应该是过载了.这个警告在mnesia dump操作会发生这个问题,表类型为disc_only_copies .disc_copies都可能会发生. 如何重现这个问题,例子的场景是多个进程同时在不断地mnesia:dirty_write/2 mnesia过载分析 1.抛出警告是在mnesia 增加dump

企业网络改造解决案例

之前给一家公司做了个网络改造项目,现在拿出来做个案例.希望对网友有所帮助. 首先介绍下这企业的基本情况.这是一家三四百人的中型公司,有三栋办公楼.一开始公司的规模比较小,拉了50M联通的独享带宽,连上交换机集线器就满足企业的网络需求,由于企业发展及业务拓展,该公司分别又拉了100M电信的独享带宽供IDC机房使用,和50M电信的独享带宽供办公区使用,同样没有经过整体的规划.随着业务发展及信息安全需求,现行的网络结构已经远远不能满足企业信息发展的需求. 改造前的网络拓扑如下: 改造前网络存在以下问题

《gis空间分析及应用案例解析》培训总结

<gis空间分析及应用案例解析>培训总结 来源:常德水情 作者:唐校准 发布日期:2014-01-02       2013年12月2630日由中国科学院计算技术研究所教育中心组织的<gis空间分析及应用案例解析>培训班在中南林业科技大学开班,由闫磊教授主讲.我有幸同经过领导批准与同事段志昊两人参加了此次培训. 这次培训的目标是:通过参加培训学习,使培训者快速掌握地理信息系统(arcgis10)的各种基本操作.新功能和新技术,以及空间数据库的有关理论.技术及应用,加强空间数据库的数

JavaScript中的ParseInt(&quot;08&quot;)和“09”返回0的原因分析及解决办法

今天在程序中出现一个bugger ,调试了好久,最后才发现,原来是这个问题. 做了一个实验: alert(parseInt("01")),当这个里面的值为01====>07时都是正常的,但是在"08","09"就会返回0 (这种现象出现在ie内核的浏览器中,如360浏览器就会出现这种错误)(谷歌,火狐不受影响). 查阅资料得知着这种现象原因: 大神的解释: 01--07自然没有问题,但是09,08都是不合格的八进制形式,所以被按照0处理了.

Netty中LineBasedFrameDecoder解码器使用与分析:解决TCP粘包问题

[toc] Netty中LineBasedFrameDecoder解码器使用与分析:解决TCP粘包问题 上一篇文章<Netty中TCP粘包问题代码示例与分析>演示了使用了时间服务器的例子演示了TCP的粘包问题,这里使用LineBasedFrameDecoder就是用来解决这个问题的. 不过需要注意的是,LineBasedFrameDecoder见名知其义,可见其是与行相关的,而在前面演示TCP粘包问题时,作者是有意在发送的消息中都加入了换行符,目的也是为了在后面去讲解LineBasedFram

python接口测试之401错误的分析和解决(十六)

作者 无涯 在接口的测试中,经常会遇到客户端向服务端发送一个请求,服务端返回401的错误,那么今天本文章就来说明在接口测试中如何分析以及解决该问题. 我们知道在HTTP返回的状态码中,401错误表示的是被请求的页面需要用户名和密码.401的错误详细的可以描述为:客户端发送请求抖到服务端, 页面需要验证服务端会返回401的错误,见如下的错误信息: 401 UNAUTHORIZED Headers Content-Type: application/jsonWWW-Authenticate: Bas

OGG-00446 分析与解决

OGG-00446 分析与解决 Table of Contents 1. 00446 1.1. Missing filename opening checkpoint file 1.1.1. 错误信息 1.1.2. 分析 1.2. could not find archived log 1.2.1. 错误信息 1.2.2. 分析 1 00446 OGG 的一些错误编号,包含了很多种不同的原因.00446 就是这样的一种,不同的原因有不同的提示.本文包含两种: Missing filename o