首先明确java堆分为perm和heap, 本文只讨论heap空间。
Eden存放新生成的对象, 它内部的对象生命周期不超过1次Minor GC。
S0、S1的S是Survivor的缩写, 它用于存放MinorGC后幸存,又不满足进入Old Generation条件的对象。为什么要有S0和S1?因为这里用的垃圾回收算法是复制算法, 具体可以查看http://my.oschina.net/xiaoqqq/blog/387327
Old Generation一般称作老年代、旧生代, 它里面存放的是生命周期超过MaxTenuringThreshold值得对象和大对象。
Minor GC即新生代GC, 它是jvm回收Eden和S0、S1内存活对象的GC过程, 他的触发条件是Eden内存不够分配新的对象。
Full GC即全局GC, 每次执行Full GC都会暂停所有用户线程,减少Full GC的执行次数是优化很重要的部分。它的触发条件是Minor GC将对象往Old Generation中移动时发现Old Generation空间不足。
在使用单线程回收器、多线程回收器、并行回收、CMS回收器的情况下(7种垃圾收集器除了G1), 通常minor GC要远快于Full GC。这是很明显的,minor GC只回收新生代, 通常都是些生命周期短的小对象, 而Full GC则回收整个heap,包括老年代中一些寿命很长的对象和大对象。
各个代的大小设置直接决定了minor GC和Full GC的触发时机, 在代大小的优化上, 主要参数包括-Xms、-Xmx、-Xmn、-XX:SurvivorRatio、-XX:MaxTenuringThreshold。
-Xms和-Xmx分别表示堆heap可以使用的最小内存和最大内存, 优化时通常将这两个值设置为相同的值, 以避免JVM不断为他们分配内存空间。其他参数到这里查看http://my.oschina.net/xiaoqqq/blog/384808
1. JVM启动参数中添加-verbose:gc -XX:+PrintGCTimeStamps -XX:+PrintGCDetails -Xloggc:./gc.log
以下内容为使用jdk7时输出, jdk版本不同, 启动参数不同显示内容会有些差异。
10.160: [GC10.160: [DefNew: 16384K->2048K(18432K), 0.0169596 secs] 16384K->16120K(131072K), 0.0618775 secs] [Times: user=0.02 sys=0.00, real=0.06 secs] 10.186: [GC10.186: [DefNew: 18432K->2048K(18432K), 0.0167307 secs] 32504K->31731K(131072K), 0.0168543 secs] [Times: user=0.02 sys=0.00, real=0.02 secs] 10.206: [GC10.207: [DefNew: 18432K->2047K(18432K), 0.0174237 secs] 48115K->48028K(131072K), 0.0175884 secs] [Times: user=0.03 sys=0.02, real=0.03 secs] 10.227: [GC10.227: [DefNew: 18431K->2047K(18432K), 0.0157971 secs] 64412K->64398K(131072K), 0.0159248 secs] [Times: user=0.01 sys=0.00, real=0.01 secs] 10.246: [GC10.246: [DefNew: 18431K->2048K(18432K), 0.0204069 secs] 80782K->80756K(131072K), 0.0205314 secs] [Times: user=0.02 sys=0.00, real=0.02 secs] 10.269: [GC10.269: [DefNew: 18432K->2048K(18432K), 0.0174500 secs] 97140K->97116K(131072K), 0.0175259 secs] [Times: user=0.02 sys=0.00, real=0.01 secs] 10.289: [Full GC10.289: [Tenured: 95068K->107060K(112640K), 0.0388235 secs] 107283K->107060K(131072K), [Perm : 2488K->2488K(21248K)], 0.0389029 secs] [Times: user=0.03 sys=0.00, real=0.03 secs] 15.319: [GC15.319: [DefNew: 16384K->16384K(18432K), 0.0000187 secs]15.319: [Tenured: 107060K->16622K(112640K), 0.0181551 secs] 123444K->16622K(131072K), [Perm : 2488K->2488K(21248K)], 0.0182582 secs] [Times: user=0.02 sys=0.00, real=0.02 secs] Heap def new generation total 18432K, used 656K [0x00000000f2c00000, 0x00000000f4000000, 0x00000000f4000000) eden space 16384K, 4% used [0x00000000f2c00000, 0x00000000f2ca4290, 0x00000000f3c00000) from space 2048K, 0% used [0x00000000f3c00000, 0x00000000f3c00000, 0x00000000f3e00000) to space 2048K, 0% used [0x00000000f3e00000, 0x00000000f3e00000, 0x00000000f4000000) tenured generation total 112640K, used 16622K [0x00000000f4000000, 0x00000000fae00000, 0x00000000fae00000) the space 112640K, 14% used [0x00000000f4000000, 0x00000000f503b948, 0x00000000f503ba00, 0x00000000fae00000) compacting perm gen total 21248K, used 2495K [0x00000000fae00000, 0x00000000fc2c0000, 0x0000000100000000) the space 21248K, 11% used [0x00000000fae00000, 0x00000000fb06fc88, 0x00000000fb06fe00, 0x00000000fc2c0000) No shared spaces configured.
DefNew是垃圾回收期类型, 即serial young collector, 因为这里在启动参数中指定了-XX:+UseSerialGC, 如果不指定则默认使用ParNewGC, 这里的值就是PSYoungGen。
以上日志说明jvm进行了8次垃圾回收, 其中7次MinorGC, 1次FullGC。FullGC行中显示本次全局回收耗时为0.0389029 secs
2. 使用jstat:
jstat -gc -h20 -t 9076 1s > jstat.log
9076是进程id
1s表示每隔1秒打印一次监控结果
1. 新生代不能太小也不能太大。 太小会导致MinorGC频繁,有些大对象直接进入老年代。 太大会导致老年代减小, 从而导致Full GC频繁。注意: 看本文最开始的图片。
以下为同一段测试程序, 新生代设置的大小不同, gc的情况:
#-Xms130M -Xmx130M -Xmn120M -XX:+UseSerialGC Timestamp S0C S1C S0U S1U EC EU OC OU PC PU YGC YGCT FGC FGCT GCT 34.4 12288.0 12288.0 0.0 0.0 98304.0 96510.2 10240.0 10240.0 21248.0 2488.3 1 0.047 2 0.109 0.157
#-Xms130M -Xmx130M -Xmn20M -XX:+UseSerialGC Timestamp S0C S1C S0U S1U EC EU OC OU PC PU YGC YGCT FGC FGCT GCT 30.8 2048.0 2048.0 0.0 0.0 16384.0 0.0 112640.0 107060.6 21248.0 2488.3 6 0.146 1 0.049 0.195
重点查看YGC(新生代gc次数)、YGCT(新生代gc耗时)、FGC(full gc次数)、FGCT(full gc耗时) 这4列
通常推荐新生代占heap空间的1/3。
2. 根据情况, 合理分配Survivor空间。
3. 合理指定新生代对象的生命周期。