jdk6和7服务器端(-server) 默认的新生的垃圾回收器为:PS Scavenge,老年代默认的垃圾回收器为:PS MarkSweep
目前项目使用jdk7,tomcat7,经常出现内存堆使用量200s持续超过堆总内存80%,触发报警。
由于项目最近的更新为jdk和tomcat升级,从6升级到7,而之前使用tomcat6时并未报警,据查是由于tomcat的一个监听器行为模式变更造成的
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
在tomcat6中,它会每隔一个小时3600s调用一次System.gc()方法,手动执行Full GC,使老年代中的无用对象每隔一小时清理一次;
在tomcat7中,事情发生了变化,它没每隔Long.Max_Value s执行一次System.gc(),这个时间太长了;
回到实际项目中,老年代持续增加,平均每天会触发1~2次Full GC,在这个工程中,老年代内存使用量长时间居高不下,而新生代的内存使用量随着业务频率的变化,有时候迅速撑满,触发Young GC;有时候又增长缓慢,如果Young Memory + Old Memory 总和超过堆内存容量的80%时,就会报警。
总的来说,老年代内存占用量长期偏高,增长较快,是导致这个问题的主要原因。
先来了解垃圾回收算法的一些术语:
PS Scavenge:新生代垃圾回收器,使用复制算法(内存分为Eden,S1,S2),并行的多线程收集器,它关注的系统的吞吐量,有效的利用cpu,尽快完成任务,不太关注线程停顿时间。它有一个自适应策略,导致虚拟机参数配置-XX:SurvivorRatio参数没有实际意义(S1,S2的大小会不定的变化),当然这也是一个参关控制的
标记-清除MarkSweep:把内存分成很多块,对象没有引用了就标记出来,标记完后统一回收对象,清除后空间不在连续,分配大对象时可能无法找到足够空间将触发一次垃圾回收
(深入理解Java虚拟机第二版图)