随着计算机的发展,我们现在使用的电脑都是多核的,进而我们希望在执行垃圾回收的时候,也充分利用多核的优势,提高垃圾回收的效率,鉴于我们的web系统通常使用的是4核8G的服务器,所以现在很多线上系统使用的是parNew+CMS垃圾回收
1、ParNew简介
新生代的ParNew垃圾回收器主打的就是多线程垃圾回收机制,另外一种Serial垃圾回收器主打的是单线程垃
圾回收,他们俩都是回收新生代的,唯一的区别就是单线程和多线程的区别,但是垃圾回收算法是完全一样的。
ParNew默认给自己设置的垃圾回收线程的数量就是跟CPU的核数是一样的,如果你一定要自己调节ParNew的垃圾回收线程数量,也是可以的,使用“-XX:ParallelGCThreads”参数可以设置线程的数量 ,但建议通常不用设置,因为单CPU运行多线程会导致频繁的线上上下文切换,有效率开销。
2、CMS简介
大纲:CMS的执行流程及特点-->在执行过程中引发的问题-->该如何优化-->为什么要设置此模板-->此模板带来的益处
一般老年代我们选择的垃圾回收器是CMS,他采用的是标记清理算法。
CMS垃圾回收流程:
初始标记:标记出来所有GC Roots直接引用的对象
并发标记:对老年代所有对象进行GC Roots追踪,其实是最耗时的
重新标记 :对在第二阶段中被系统程序运行变动过的少数对象进行标记
并发清理:清理掉之前标记为垃圾的对象
各阶段的特点:
阶段 | stop the world | 耗时
初始标记 | true | 短
并发标记 | false | 长
重新标记 | true | 短并发清理 | false | 长
思考问题:
- 为什么parNew使用的是STW之后,整体进行复制清除,而老年代却要分阶段处理呢?
- CMS为什么要设计这几个阶段,少其中任何一个阶段可以吗?
- 如果CMS垃圾回收期间,系统程序要放入老年代的对象大于了可用内存空间,此时会如何?
- CMS使用的是标记清除算法,内存碎片该如何优化呢?
2.1、优化:
1、如果CMS垃圾回收期间,系统程序要放入老年代的对象大于了可用内存空间,此时会如何?
这个时候,会发生Concurrent Mode Failure,就是说并发垃圾回收失败了,我一边回收,你一边把对象放入老年代,内存都不够了。 此时就会自动用“Serial Old”垃圾回收器替代CMS,就是直接强行把系统程序“Stop the World”,重新进行长时间的GC Roots追 踪,标记出来全部垃圾对象,不允许新的对象产生 然后一次性把垃圾对象都回收掉,完事儿了再恢复系统线程。切换到“Serial Old”垃圾回收器执行是非常缓慢的,
“-XX:CMSInitiatingOccupancyFaction”:可以用来设置老年代占用多少比例的时候触发CMS垃圾回收,老年代占用了92%空间了,就自动进行CMS垃圾回收,预留8%的空间给并发回收期间,系统程序把一些新对象放入老年代 中。
所以在生产实践中,“-XX:CMSInitiatingOccupancyFaction”需要合理设置一下,避免“Concurrent Mode Failure”问题。
2、内存碎片问题
老年代的CMS采用“标记-清理”算法,会导致大量的内存碎片产生。会导致后续对象进入老年代找不到可用的连续内存空间了,然后触发Full GC。提高FullGC触发频率。
CMS有一个参数是“-XX:+UseCMSCompactAtFullCollection”,默认就打开了,意思是在Full GC之后要再次进行“Stop the World”,停止工作线程,然后进行碎片整理,就是把存活对象挪到一起,空出来大片
连续内存空间,避免内存碎片。
还有一个参数是“-XX:CMSFullGCsBeforeCompaction”,这个意思是执行多少次Full GC之后再执行一次内存碎片整理的工作,默认
是0,意思就是每次Full GC之后都会进行一次内存整理。
2.2、ParNew + CMS参数模板
为什么设置此模板?
- JVM默认配置使用的内存是非常小的,不利于线上系统的正常运行;
- 很多人不了解JVM,不知道参数该如何设置;
- 为了以后自己使用方便
使用此模板的好处?
- 对于通常的web系统,各区域大小设置的较为合理,可防止存活时间短的对象进入老年代,频繁触发FullGC;
- 虽然每次fullGC之后,都会对内存进行整理,增加了GC时间的,但是降低了fullGC触发的频率,整体是划算的;
- eden和survivor使用的是默认比例,可以通过jstat 查看每次gc的情况,适当的调整
服务器配置4核8G,参数模板
-Xms4096M -Xmx4096M -Xmn3072M -Xss1M -XX:PermSize=256M -XX:MaxPermSize=256M -XX:+UseParNewGC -
XX: + UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFaction=92 -XX: + UseCMSCompactAtFullCollection -
XX:CMSFullGCsBeforeCompaction=0 -XX:+CMSParallellnitialMarkEnabled -XX:+CMSScavengeBeforeRemark模板参数解析:
1、因为要预留一部分内存给服务器,所以设置的堆内存为4G;
2、新生代分配了3G内存,为了增大survivor区大小,防止因为动态对象年龄判断或老年代担保,使对象进入老年代。
3、虚拟机栈设置为1M,防止因调用过多,导致栈内存溢出;
4、CMS垃圾回收触发时机,通常配置92;
5、每次CMS之后整理压缩,防止内存碎片;
6、“-XX:+CMSParallellnitialMarkEnabled” 开启ParNew新生代并发清理