垃圾收集器
Serial收集器(新生代):单线程,工作时必须暂停其他线程(stop the world),单线程效率最高,适用于client模式下的虚拟机。
ParNew即Parallel New收集器(新生代):Serial收集器的多线程版本,唯一能与CMS收集器结合使用的收集器,默认GC线程数与CPU数量相同,可通过-XX:ParallelGCThreads参数来限制垃圾回收的线程数。
Parallel Scavenge收集器(新生代):注重可控制的吞吐量。(运行用户代码时间/(运行用户代码时间+垃圾收集时间)),适合少交互的后台运算。-XX:MaxGCPauseMillis设置最大垃圾收集停顿时间(代价:牺牲吞吐量与新生代空间,新生代调小会导致GC频繁)、XX:GCTimeRatio设置吞吐量大小、-XX:+UseAdaptiveSizePolicy(系统根据性能监控信息,动态调整参数)。自适应调节策略是Parallel Scavenge和ParNew的重要区别。
Serial Old收集器(老年代):Serail收集器的老年代版本。使用标记-整理算法。用途:在JDK1.5之前与Parallel Scavenge搭配使用、作为CMS收集器后备预案(发生Concurent Mode Failure)。
Parallel Old收集器(老年代):Parallel Scavenge收集器的老年代版本,使用“标记-整理”算法,用于注重吞吐量以及CPU资源敏感的场合
CMS收集器(老年代):分为初始标记(STW)、并发标记、重新标记(STW)、并发清除。
详情参考,巨巨说的很明白了。CMS收集器详解
G1收集器:G1收集器,还没看懂,还要反回去看。
内存分配与回收策略
1.对象优先在eden分配
当eden空间不足以分配的时候,则发生mirror gc。当Mirror gc发现已有的对象无法放入survivor区时,通过担保机制将已有对象转移到老年区。(SerialGC、ParNewGC)
-XX:+PrintGCDetails -XX:+UseSerialGC -Xms20m -Xmx20m -Xmn10m -XX:SurvivorRatio=8
2.大对象直接在老年代分配
-XX:+PretenureSizeThreshold,当大于这个设置值的对象,直接在老年代分配(SerialGC、ParNewGC)。
-XX:+PrintGCDetails -XX:+UseSerialGC -Xms20m -Xmx20m -Xmn10m -XX:SurvivorRatio=8 -XX:PretenureSizeThreshold=3145728
3.长期存活的对象将进入老年代
若对象在eden出生,经过第一次GC能进入survivor区,仍然存活,则岁数为1。每一次存活,则岁数+1。MaxTenuringThreshold该参数指定了岁数到多少的新生代对象将进入老年代。
-verbose:gc -XX:+UseSerialGC -Xms20m -Xmx20m -Xmn10m -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=1 -XX:+PrintTenuringDistribution
public static void testTenuringThreshold(){
byte[] a1,a2,a3;
a1= new byte[oneMB/4];
a2=new byte[oneMB*4];
a3=new byte[oneMB*4];
a3=null;
a3=new byte[oneMB*4];
}
[GC (Allocation Failure) [DefNew
Desired survivor size 524288 bytes, new threshold 1 (max 1)
- age 1: 981656 bytes, 981656 total
: 6505K->958K(9216K), 0.0038322 secs] 6505K->5054K(19456K), 0.0038761 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
//第一次GC,Allocation Failure表明是因为无法分配eden内存产生的GC,即无法给a3在eden空间分配内存,此时,由于a1
[GC (Allocation Failure) [DefNew
Desired survivor size 524288 bytes, new threshold 1 (max 1)
- age 1: 2136 bytes, 2136 total
: 5138K->2K(9216K), 0.0020616 secs] 9234K->5052K(19456K), 0.0020883 secs] [Times: user=0.02 sys=0.00, real=0.00 secs]
Heap
def new generation total 9216K, used 4317K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
eden space 8192K, 52% used [0x00000000fec00000, 0x00000000ff036bb0, 0x00000000ff400000)
from space 1024K, 0% used [0x00000000ff400000, 0x00000000ff400858, 0x00000000ff500000)
to space 1024K, 0% used [0x00000000ff500000, 0x00000000ff500000, 0x00000000ff600000)
tenured generation total 10240K, used 5050K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
the space 10240K, 49% used [0x00000000ff600000, 0x00000000ffaeeab8, 0x00000000ffaeec00, 0x0000000100000000)
Metaspace used 3366K, capacity 4496K, committed 4864K, reserved 1056768K
class space used 369K, capacity 388K, committed 512K, reserved 1048576K
//第二次GC,a1由于年龄到了1岁,则进入老年代,则survivor used 0%(From Survivor区域与To Survivor区域是交替切换空间,在同一时间内两者中只有一个不为空),a3old被gc,a3new则在eden区生成
4.动态对象年龄判定
若survivor区中,size[o1]+size[o2]+……+size[on]>=survivor/2,且age[o1]==age[o2]==……==age[on],则o1,o2,o3……on一起进入老年区。此时并不需要o1.age>=MaxTenuringThreshold
-verbose:gc -XX:+UseSerialGC -Xms20m -Xmx20m -Xmn10m -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=15 -XX:+PrintTenuringDistribution
public static void testTenuringThreshold2() {
byte[] a1, a2, a3, a4;
a1 = new byte[oneMB / 4];
a2 = new byte[oneMB / 4];
a3 = new byte[oneMB * 4];
a4 = new byte[oneMB * 4];
a4 = null;
a4 = new byte[oneMB * 4];
}
5.空间分配担保
用于minorGC前的检查策略。-XX:HandlePromotionFailure=true
在JDK6 update24后,废弃HandlePromotionFailur,即老年代连续最大空间>新生代所有对象总大小,或大于历次晋升对象平均大小,则进行minorGC,否则进行fullGC