JVM性能调优(二):垃圾回收算法

一、Throughput收集器

1、Throughput回收算法,即为多线程回收算法, 新老代回收时均需要 stop the world      

使用 -XX:+ UseParallelGC、- XX:+ UseParallelOldGC 标志启用 Throughput 收集 器。

2、Throughput回收算法,分为对新生代的Minor gc 和对老年代的full gc,其中full gc会对新生代清空。

      程序调用System.gc后的,gc日志如下:

[GC (System.gc()) [PSYoungGen: 3692K->1848K(38400K)] 3692K->1856K(125952K), 0.0017672 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (System.gc()) [PSYoungGen: 1848K->0K(38400K)] [ParOldGen: 8K->1648K(87552K)] 1856K->1648K(125952K), [Metaspace: 3413K->3413K(1056768K)], 0.0037741 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 

3、 《JAVA性能权威指南》中有对minor gc和 full  gc的描述如下:Throughput 收集器有两个基本的操作: 其一 是回收新生代的 垃圾, 其二是回收老年代的垃圾。

如下图:minor GC前后的变化

如下图:full GC前后的变化,full gc会对新生代对象全部回收,清空

4、除了静态设置固定的堆大小外,还可以通过设置最大停顿时间和GC运行占比进行GC控制,jvm根据设置自动调整新老代堆大小,设置方法如下:- XX: MaxGCPauseMillis= N 和 -XX: GCTimeRatio= N

大多数应用,设置性能要求就能满足要求。通过测试设置静态堆大小能获得最优的性能。

二、CMS 收集器

1、CMS 收集器设计的初衷是为了消除Throughput 收集器和Serial收集器Full GC周期中的长时间停顿。 CMS收集器在Minor GC时会暂停所有的应用线程, 并以多线程的方式进行垃圾回收。  这其中最显著的不同是, CMS不再使用 Throughput 的收集算法(- XX:+ UseParallelGC),改用新的算法来收集新生代对象,启动标识:

-XX:+UseConcMarkSweepGC   和   -XX:+UseParNewGC

CMS并发收集后不会对老年代进行压缩整理,会产生内容碎片

2、CMS垃圾回收过程 

1)初始标记 CMS Initial Mark

标记GC ROOT能直接关联到的对象 ; Stop the world ; 速度快,内存不变化

[GC (CMS Initial Mark) [1 CMS-initial-mark: 72333K(87424K)] 83197K(126848K), 0.0002953 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]

2)并发标记  CMS-concurrent-mark

标记出待回收对象 ; concurrent ; 速度慢,内存不变化(程序新产生的对象会使新生代增加)

[CMS-concurrent-mark-start]
[CMS-concurrent-mark: 0.001/0.001 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 

3) 预清理 CMS-concurrent-preclean

并发预处理阶段做的工作还是标记,与后面的重标记功能相似。既然相似为什么要有这一步?CMS是以获取最短停顿时间为目的的GC。重标记需要STW(Stop The World),因此重标记的工作尽可能多的在并发阶段完成来减少STW的时间。此阶段标记从第2步,并发标记阶段,新生代晋升的对象新分配到老年代的对象以及在并发阶段被修改了的对象

[CMS-concurrent-preclean-start]
[CMS-concurrent-preclean: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 

4) 重标记

(STW)  暂停所有用户线程,重新扫描堆中的对象,进行可达性分析,标记活着的对象。

重新标记分为多个阶段

(a)、可中段预处理,此过程是为了防止minor STW后,重新标记接着STW,详细介绍见:http://www.cnblogs.com/littleLord/p/5380624.html#remark 

[CMS-concurrent-abortable-preclean-start]
 CMS: abort preclean due to time [CMS-concurrent-abortable-preclean: 0.139/5.055 secs] [Times: user=0.00 sys=0.00, real=5.06 secs] 
[GC (CMS Final Remark) [YG occupancy: 11247 K (39424 K)][Rescan (parallel) , 0.0004075 secs][weak refs processing, 0.0000186 secs][class unloading, 0.0006072 secs][scrub symbol table, 0.0007691 secs][scrub string table, 0.0001933 secs][1 CMS-remark: 72333K(87424K)] 83581K(126848K), 0.0021374 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
有了前面的基础,这个阶段的工作量被大大减轻,停顿时间因此也会减少。注意这个阶段是多线程的。

 5) 并发清理 CMS-concurrent-sweep

用户线程被重新激活,concurrent , 同时清理那些无效的对象。

[CMS-concurrent-sweep-start]
[CMS-concurrent-sweep: 0.000/0.000 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 

6)  CMS-concurrent-sweep 

CMS清除内部状态,为下次回收做准备,concurrent。

如何解决并发过程中,引用变化与老年代引用新生代的部问题?

http://www.cnblogs.com/littleLord/p/5380624.html#remark 有关于card table的描述,非常好。

2、CMS调优级目标

  • CMS 垃圾 回收 有多个操作, 但是期望的操作 是 Minor GC 和并发回收( concurrent cycle)。
  • CMS 收集过程中的并发模式失效以及晋升失败的代价都非常昂贵,会进行一次STW的FULL GC ,我们应该尽量调优CMS 收集器 以避免发生这些情况
  •  默认情况下CMS收集器不会对永久代进行垃圾回收。

3、并发失效的调优

CMS在进行回收时,如果老年代空间不够,会发生并行失效,所经要进行以下调优。

1) 增大堆内存

    调整方式见    JVM性能调优(一)

 2) 尽早的进行CMS回收

标志:- XX: CMSInitiatingOccupancyFraction= N 和 -XX:+ UseCMSInitiatingOccupancyOnly。

CMSInitiatingOccupancyFraction不能太小,如果设置为0,CMS会不停运行,占用CUP资源,还会多次引起STW 。根据测试情况决定,但最小最好不要小于20%

3) 调整CMS的线程数

-XX: ConcGCThreads= N 标志,增加后台线程的数目。

ConcGCThreads 的值是依据ParallelGCThreads标志的值计算得到的: ConcGCThreads = (3 + ParallelGCThreads) / 4

三、G1收集器

1、G1将新生代,老年代的物理空间划分取消了。

-XX:+UseG1GC -Xmx32g -XX:MaxGCPauseMillis=200

其中-XX:+UseG1GC为开启G1垃圾收集器,-Xmx32g 设计堆内存的最大内存为32G,-XX:MaxGCPauseMillis=200设置GC的最大暂停时间为200ms。如果我们需要调优,在内存大小一定的情况下,我们只需要修改最大暂停时间即可。

2、G1收集器过程(主要是以下四步)

  • 新生代垃圾收集: 
  • 后台收集,并发周期:主要做标记,标记哪些老件代的region可以回收 
  • 混合式垃圾收集:回收上面标记的region与新生代
  • 必要时的FULL GC: 需要调优避免的收集方式 

第二步过程如下(后台收集,并发周期:主要做标记,标记哪些老件代的region可以回收) 

1)扫描根分区  (STW) , 类似与CMS的初始标记

[GC concurrent-root-region-scan-start]
[GC concurrent-root-region-scan-end, 0.0009198 secs]

2)并发标记 , concurent

[GC concurrent-mark-start]
[GC concurrent-mark-end, 0.0016649 secs]

3) 重新标记,正常清理 (SWT)

[GC remark [Finalize Marking, 0.0002969 secs] [GC ref-proc, 0.0001526 secs] [Unloading, 0.0011846 secs], 0.0020493 secs]
 [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC cleanup 70M->70M(128M), 0.0005665 secs]
 [Times: user=0.00 sys=0.00, real=0.00 secs] 

第三步 (混合式垃圾收集)

79. 826: [GC pause (mixed), 0. 26161600 secs]

 [Eden: 1222M( 1222M)-> 0B( 1220M) Survivors: 142M-> 144M Heap: 3200M( 4096M)-> 1964M( 4096M)] [Times: user= 1. 01 sys= 0. 00, real= 0. 26 secs]

3、并发模式失效

1) 在上面的第二步执行时:G1垃圾收集启动标记周期, 但老年代在周期完成之前就被填满,在这种情况下,G1收集器会放弃标记周期。

2)在上面的第三步执行时:G1收集器完成了标记阶段, 开始启动混合式垃圾回收, 清理老年代的分区, 不过,老年代空间在 垃圾回收释放出足够内存之前就会被耗尽。

3)(疏散失败)进行新生代垃圾收集时, Survivor空间和老年代中没有足够的空间容纳所有的幸存对象。这种情况在GC日志中通常被当做一种特别的情况:

60. 238: [GC pause (young) (to- space overflow), 0. 41546900 secs]

4)巨型对象分配失败:使用G1收集器时, 分配非常巨大对象的应用程序可能会遭遇另一种Full GC;

[GC pause (G1 Humongous Allocation) (young) (initial-mark), 0.0018790 secs]

4、G1 的调优

1)通过增加总的堆 空间大小或者调整老年代、 新生代之间的比例来增加老年代空间的小。

Xmx32g -XX:MaxGCPauseMillis=200

2)增加后台线程的数目( 假设我们有足够的CPU资源运行这些线程)。

3)以更高的频率进行G1的后台垃圾收集活动。

-XX: InitiatingHeapOccupancyPercent= N  , 设置G1启动的时机,总堆大小的比例

并发周期结束之后, 检查下堆的大小, 确保 InitiatingHeapOccupancyPercent 的值大于此时堆的大小。

4)在混合式垃圾回收周期中完成更多的垃圾收集工作。

调整JVM标记应该回收老年代的region的参数,认为垃圾比例大于 多少,可进行回收。

-XX: G1MixedGCCountTarget= N 

调整回收周期,几个周期内把标记的垃圾回收完成

-XX: G1MixedGCCountTarget= N

调整可以忍受的回收周期

MaxGCPauseMillis

5、G1调优总结

(1) 作为G1收集器调优的第一步, 首先应该设定一个合理的停顿时间作为目标。

(2)如果使用这个设置后, 还是频繁发生Full GC, 并且堆的大小没有扩大的可能, 这时就需要针对特定的失败采用特定的方法 进行调 优。  

        a. 通过 InitiatingHeapOccupancyPercent 标志可以调整G1收集 器, 更频繁地启动后台垃圾收集线程。  

        b. 如果有充足的CPU 资源, 可以考虑调整 ConcGCThreads 标志, 增加垃圾收集线程 数。  

       c. 减小 G1MixedGCCountTarget 参数可以避免晋升失败。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值