wujiangping 2013-04-21
1、基本概念
heap=young+old,不包括perm区
young=eden+from_survivor+to_survivor,实际可用的大小是eden+to_survivor
串行收集器-单cpu使用,相对高效
并行收集器-多cpu,吞吐量优先时使用
并发收集器-多cpu,停顿时间优先时使用(web应用一般用这个)
2、基本JVM参数
-Xmx64m最大heap大小,默认物理内存的1/4(但是限制<1GB)
-Xms64m初始heap大小,默认物理内存的1/64(但是限制<1GB)
-Xmn12myoung代大小,sun推荐整个heap的3/8,太大会减少old的大小,引发较频繁的majorgc
-Xss256k每个线程的堆栈大小,一般256就ok了
-XX:SurvivorRatio=16eden与一个survivor的比值,默认是8
-XX:+DisableExplicitGC关闭System.gc()
3、CMS收集相关参数
-XX:+UseConcMarkSweepGC使用CMS内存收集
-XX:+UseCMSCompactAtFullCollection在fullgc的时候,对old区压缩
-XX:CMSFullGCsBeforeCompaction=1多少次fullgc后进行old区压缩,cms会产生old区"碎片",要进行整理,避免没有连续空间放大对象而引发cmsfailure出现
-XX:CMSInitiatingOccupancyFraction=70old区使用70%后开始CMS收集,jdk5默认68%,jdk6默认92%
-XX:CMSInitiatingPermOccupancyFraction=70perm区使用70%后开始CMS收集,jdk5默认68%,jdk6默认92%
-XX:+CMSClassUnloadingEnabled允许perm区不够引发fullgc时perm区的类卸载
-XX:+UseParNewGC设置年轻代为并行收集
-XX:ParallelGCThreads=4并行收集器的线程数,此值最好配置与处理器数目相等
-XX:MaxTenuringThreshold=3垃圾最大年龄,jdk5之前,cms收集器默认为0,jdk6默认为4
4、GC日志辅助参数
-XX:+PrintGCDetails输出gc详细信息
-XX:+PrintGCTimeStamps输出gc时间戳,java6之后使用-XX:+PrintGCDateStamps,阅读更方便
-Xloggc:filenamegc日志文件路径
-XX:+PrintTenuringDistributionsurvivor的对象进入old区之前进行了几次copy,与设置的-XX:MaxTenuringThreshold比较,调整此值和survivor大小
5、各个参数调整经验
heap大小:在保证os顺畅运转的前提下,heap尽量大。
young区:
尽量大,过小可能引发频繁majorgc,降低吞吐量,同时可能导致对象直接进入old区,如果old满了,触发fullgc;
过大会引起回收耗时过长,导致应用停顿,gui程序不要太大的young区。
old区:
过大会导致old回收过慢,应用停顿较长(实际上cms回收是很快的,所以尽量大些,减少cmsgc频率);
过小会导致产生old区小碎片,放不下大对象,引起频繁fullgc。
如果用了缓存,old区要适当大些,同时缓存不应该无限增长。
young与old的调整原则:要考虑old区的耗时、频率,尽可能降低这两个值。
6、minorgc,回收young区
当young代满了(即eden区放不下新创建的对象),触发minorgc,只回收young区的对象,old区不回收。
young区被回收的对象越多,gc速度越快,因为young区采用的是“复制”的方式,即把enden区和survivor的from区存活对象复制到survivor的to区。
如果设置了-XX:MaxTenuringThreshold=N参数,survivor的from区对象到to的复制达到了N次,进入old区,如果to区装不下,直接进入old区。
关于promotionfailed:
引发的两个原因:
1)survivor太小了,survivor里面的对象还没有到达进入old的copy次数
2)进入old区的对象太多,而old区已经不够用了
这两个情况都会引发fullgc,导致停顿较长。
第一个可以调整survivor的大小,或者直接去掉-XX:MaxTenuringThreshold参数,minorgc回收不掉直接进入old区;
第二个可以调小young、增大old的大小(尽早触发minorgc,减少每次进入old的对象数量),或者调小-XX:CMSInitiatingOccupancyFraction(尽早触发old的回收)
7、cmsgc,回收old区
步骤:initial-mark>concurrent-mark>concurrent-preclean>remark>concurrent-sweep>concurrent-reset
除了initial-mark、remark之外,不暂停应用。
关于concurrentmodefailure:
引发的两个原因
1)年老代变满之前,old区垃圾回收还没有完成
2)新空间分配请求在年老代的剩余空间中无法得到满足,日志:[GC90010.628:[ParNew:261760K->261760K(261952K),0.0000350secs]90010.628:[CMS(concurrentmodefailure)
第一个需要调小old区,或者调小参数-XX:CMSInitiatingOccupancyFraction=70,以尽快回收old区,减少old回收时间;
第二个需要减少young、增加old的大小,或者使用-XX:CMSFullGCsBeforeCompaction并设置较小的值,提高fullgc后压缩old的频次,避免young大对象无法晋升到old。
参考文献:
http://www.cnblogs.com/redcreen/archive/2011/05/04/2037057.html
http://www.oracle.com/technetwork/java/javase/gc-tuning-6-140523.html
http://blog.csdn.net/sfdev/article/details/4483442
http://blog.csdn.net/cpzhong/article/details/6912272