cms java内存,CMS内存回收机制分析

作者:李宏旭,新炬网络高级技术专家。

一、 背景

针对大内存对象引起的内存回收机制分析,单个实例内存配置为20G。

二、 思路

1.java虚拟机运行时的数据区

fe8f353ad79c4121728fe2669c290509.png

下文针对的内存回收指的是“由所有线程共享的数据区”。

2.内存情况分析

l  抓取cpu占用top10的线程分析:

线程编号

cpu占用率

堆栈日志对应十六进制编号

对应线程

18159

92%

46ef

"Gang worker#0 (Parallel CMS Threads)" prio=10 tid=0x00002aaaae64a000 nid=0x46ef runnable

18160

87%

46f0

"Gang worker#1 (Parallel CMS Threads)" prio=10 tid=0x00002aaaae64c000 nid=0x46f0 runnable

12870

20%

3246

"http-9090-770" daemon prio=10 tid=0x00002aaaf7f78800 nid=0x3246 runnable [0x00002aab1fb13000]

java.lang.Thread.State: RUNNABLE

at java.net.SocketInputStream.socketRead0(Native Method)

12795

18%

31fb

"http-9090-713" daemon prio=10 tid=0x00002aaaddca9800 nid=0x31fb runnable [0x00002aab24c66000]

java.lang.Thread.State: RUNNABLE

at java.net.SocketInputStream.socketRead0(Native Method)

2019

16%

7E3

"http-9090-685" daemon prio=10 tid=0x00002aab18b26000 nid=0x7e3 runnable [0x00002aab1b30a000]

java.lang.Thread.State: RUNNABLE

at java.net.SocketInputStream.socketRead0(Native Method)

31162

12%

79ba

"http-9090-357" daemon prio=10 tid=0x00002aaae8e98800 nid=0x79ba runnable [0x000000006476d000]

java.lang.Thread.State: RUNNABLE

at java.net.SocketInputStream.socketRead0(Native Method)

32225

12%

7de1

"http-9090-522" daemon prio=10 tid=0x00002aaae8d09800 nid=0x7de1 runnable [0x00002aab0af6c000]

java.lang.Thread.State: RUNNABLE

at java.net.SocketInputStream.socketRead0(Native Method)

15626

12%

3d0a

"http-9090-1001" daemon prio=10 tid=0x00002aab18ab7000 nid=0x3d0a runnable [0x00002aab33750000]

java.lang.Thread.State: RUNNABLE

at java.net.SocketInputStream.socketRead0(Native Method)

19154

11%

4ad2

"http-9090-93" daemon prio=10 tid=0x00002aaac0bb6000 nid=0x4ad2 runnable [0x0000000078eb3000]

java.lang.Thread.State: RUNNABLE

at java.net.SocketInputStream.socketRead0(Native Method)

19544

11%

4c58

"http-9090-142" daemon prio=10 tid=0x00002aaaccc78800 nid=0x4c58 runnable [0x00002aaacdd07000]

java.lang.Thread.State: RUNNABLE

at java.net.SocketInputStream.socketRead0(Native Method)

从上表数据中可以看出占用最高的两个线程都为java虚拟机CMS-concurrent-sweep内存回收线程,分析CMS内存回收情况。

分析现网java虚拟机内存回收过程。

1)研究了GC日志,发现并发gc线程[CMS-concurrent-sweep]在系统重启后,随着时间的推移,回收的越来越频繁。而且占用的CPU也越来越高。

例如:在忙时几乎每60秒就要执行一次。而每次执行一次并发GC,整个过程(从mark->清理->remark)却需要50秒左右。每次内存回收需要耗的CPU,mark过程在200%左右,清理在100%左右。

忙时并发GC的频度见下图:

9c9dfa6e5c188331c5e505a9f7a0118e.png

GC线程使用的CPU:

[CMS-concurrent-mark: 28.143/232.825 secs] [Times: user=297.77 sys=31.11, real=232.82 secs]

[CMS-concurrent-sweep: 15.029/16.950 secs] [Times: user=106.31 sys=3.51, real=16.95 secs]

而重启过的,GC频度以及消耗的CPU都要小很多。

这些点忙时GC的频度将下图:

2cdb932a9b4dbcbbfa397ded2ef8ebd2.png

GC线程使用的CPU:

[CMS-concurrent-mark: 18.635/19.500 secs] [Times: user=102.28 sys=2.93, real=19.50 secs]

[CMS-concurrent-sweep: 10.204/11.347 secs] [Times: user=51.17 sys=1.64, real=11.35 secs]

2)缓存的部分数据是惰性加载的,所以在重启实例释放内存数据后,缓存使用的空间随数据量加载会越来越大。让内存回收变得频繁。这也能解释,为什么重启系统后的几天,CPU不会占用过高。但是运行几天后,CPU就慢慢上涨。

定位结论:

引发CPU高的原因是内存回收线程导致。应用代码逻辑不存在内存泄露,但是调用量高时,会引发高频度的并发GC。高频度的并发GC会导致CPU增高。

三、 CMS介绍

CMS(ConcurrentMark-Sweep)是以牺牲吞吐量为代价来获得最短回收停顿时间的垃圾回收器。对于要求服务器响应速度的应用上,这种垃圾回收器非常适合。在启动JVM参数加上-XX:+UseConcMarkSweepGC,这个参数表示对于老年代的回收采用CMS。CMS采用的基础算法是:标记—清除。

CMS过程:

l  初始标记(STWinitialmark)

l  并发标记(Concurrentmarking)

l  并发预清理(Concurrentprecleaning)

l  重新标记(STWremark)

l  并发清理(Concurrentsweeping)

l  并发重置(Concurrentreset)

初始标记:在这个阶段,需要虚拟机停顿正在执行的任务,官方的叫法STW(StopTheWord)。这个过程从垃圾回收的"根对象"开始,只扫描到能够和"根对象"直接关联的对象,并作标记。所以这个过程虽然暂停了整个JVM,但是很快就完成了。

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

并发预清理:并发预清理阶段仍然是并发的。在这个阶段,虚拟机查找在执行并发标记阶段新进入老年代的对象(可能会有一些对象从新生代晋升到老年代,或者有一些对象被分配到老年代)。通过重新扫描,减少下一个阶段"重新标记"的工作,因为下一个阶段会StopTheWorld。

重新标记:这个阶段会暂停虚拟机,收集器线程扫描在CMS堆中剩余的对象。扫描从"跟对象"开始向下追溯,并处理对象关联。

并发清理:清理垃圾对象,这个阶段收集器线程和应用程序线程并发执行。

并发重置:这个阶段,重置CMS收集器的数据结构,等待下一次垃圾回收。

CSM执行过程:

ff63eef92f4114bbe064b002546d6a59.png

分析:

1.忙时用户线程本身消耗cpu大。

2.忙时CMS并回收与用户线程并发进行。

3.忙时CMS回收的频率高,上面分析例子中可以看到,基本上一分钟就会有一次,一次40秒左右,那么忙时基本就是用户线程与并发回收线程伴随进行的状态。这也就导致了在忙时cpu占用一直居高不下。

四、 优化方案

1.降低CMS的回收频率。

(1).减小在oscache中缓存的数据量,让更多的数据从memcache中获取,已减小jvm老生代的内存占用率,减小内存回收时对于系统的压力。

(2)在内存回收中增加内存回收时增加Survivor(救生区),以减缓老生代内存的增长速度(增加参数-XX:SurvivorRatio=6-XX:MaxTenuringThreshold=3,将Survivor区与Eden区的比率调整为1:1:5),让更多的临时对象在新生代就被回收,减缓老生代的内存的增长速度,达到降低内存回收频度的目的。

(3)调整jvm参数CMSInitiatingOccupancyFraction原先是71现在调整为75。(此参数是控制虚拟机开始回收内存的阀值),稍微调大一些,减少回收频率。

2. 降低单次CMS回收的消耗。

(1)将并发内存回收时启动线程数,从12个修改为8个,以减小内存回收时对于系统的压力。

(2)修改参数CMSFullGCsBeforeCompaction = 0 为CMSFullGCsBeforeCompaction = 2,经过两次fullgc后才进行压缩,而不是每次fullgc后都压缩。

优化前后JVM参数配置

参数

参数说明

优化前参数

优化后参数

jdk版本

现网jdk版本号

jdk1.6.0_24

jdk1.6.0_24

Xmn

Young(年轻代)分配大小

Xmn2048M

Xmn2048M

Xms

java堆初始值

Xms12288M

Xms12288M

Xmx

java堆最大值

Xmx12288M

Xmx12288M

XX:PermSize

持久代初始大小

XX:PermSize=512M

XX:PermSize=512M

UseParNewGC

设置年轻代为并行收集

XX:+UseParNewGC

XX:+UseParNewGC

UseConcMarkSweepGC

设置老生代并发回收

XX:+UseConcMarkSweepGC

XX:+UseConcMarkSweepGC

CMSParallelRemarkEnabled

降低标记停顿

CMSParallelRemarkEnabled

CMSParallelRemarkEnabled

UseCMSCompactAtFullCollection

在FULLGC的时候,压缩内存,减少碎片

UseCMSCompactAtFullCollection

UseCMSCompactAtFullCollection

CMSFullGCsBeforeCompaction

设置多少次fullgc后进行内存压缩

CMSFullGCsBeforeCompaction=0每次fullgc后都进行压缩

CMSFullGCsBeforeCompaction=2

XX:SurvivorRatio

年轻代中Eden区与两个Survivor区的比值。注意Survivor区有两个。如:3,表示Eden:Survivor=3:2,一个Survivor区占整个年轻代的1/5

Survivor=65535

SurvivorRatio=5

MaxTenuringThreshold

控制对象能经历多少次MinorGC才晋升到旧生代

MaxTenuringThreshold=0

MaxTenuringThreshold=3

ParallelGCThreads=20

设置并行垃圾回收的线程数

ParallelGCThreads=12

ParallelGCThreads=8

CMSInitiatingOccupancyFraction=N

使用cms作为垃圾回收

使用N%后开始CMS收集

CMSInitiatingOccupancyFraction=71

CMSInitiatingOccupancyFraction=80

五、 实施效果

优化方案实施前:

4d18ea506951c56b88d21c3180ada61f.png

优化方案实施后:

7b7d040c7684ec55945ed7df95d4c057.png

对比实施前后cpu的消耗情况,优化前的忙时(22点-23点)平均使用率在60%,峰值超过80%,而优化方案实施后忙时(22点-23点)平均使用率在50%,峰值在70%左右。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值