JVM的内存分配策略主要有:
- 对象优先分配在Eden上;
- 大对象直接分配在老年代;
- 长期存活的对象将直接分配在老年代;
- 动态年龄判定;
- 空间分配担保;
示例:优先分配与大对象
该示例用到的策略有“对象优先分配在Eden上”、“大对象直接分配在老年代”。
【示例代码】
使用固定的堆大小20M,新生代10M,老年代10M,设置Eden:Survivor=8:1,并输出GC详情,
/**
* @author lingbao08
* @DESCRIPTION JDK7/8 默认PS/Par Old收集器组合
* VM Args:-verbose:gc -Xms20m -Xmx20m -Xmn10m -XX:+PrintGCDetails -XX:SurvivorRatio=8
* @create 2018/7/8 17:13
**/
public class testGC1 {
public static final int _1MB=1024*1024;
public static void main(String[] args) {
byte[] a1,a2,a3,a4;
a1 = new byte[2*_1MB];
a2 = new byte[2*_1MB];
a3 = new byte[2*_1MB];
a3 = new byte[4*_1MB];
}
}
【参数说明】
-verbose:gc:输出虚拟机情况的开关。
-Xms20m:堆最小为20M。
-Xmx20m:堆最大值为20M。
-Xmn10m :年轻代为10M。
-XX:+PrintGCDetails:打印出GC详情。
-XX:SurvivorRatio=8:Eden:Survivor=8:1。(2个Survivor)
【运行结果】
Heap
PSYoungGen total 9216K, used 7641K [0x00000007ff600000, 0x0000000800000000, 0x0000000800000000)
eden space 8192K, 93% used [0x00000007ff600000,0x00000007ffd76590,0x00000007ffe00000)
from space 1024K, 0% used [0x00000007fff00000,0x00000007fff00000,0x0000000800000000)
to space 1024K, 0% used [0x00000007ffe00000,0x00000007ffe00000,0x00000007fff00000)
ParOldGen total 10240K, used 4096K [0x00000007fec00000, 0x00000007ff600000, 0x00000007ff600000)
object space 10240K, 40% used [0x00000007fec00000,0x00000007ff000010,0x00000007ff600000)
PSPermGen total 21504K, used 2997K [0x00000007f9a00000, 0x00000007faf00000, 0x00000007fec00000)
object space 21504K, 13% used [0x00000007f9a00000,0x00000007f9ced708,0x00000007faf00000)
【结果分析】
在PS/Par Old组合中,给a1、a2、a3分配的各2M内存会直接进入PSYoungGen(新生代)的Eden空间,给a4分配时,发现内存够,进行GC,此时发现Survivor空间的内存也不够使用,这是就把a4直接分配在ParOldGen(老年代)中。
示例2:长期存活对象和动态年龄判定
该示例用到的策略有“长期存活的对象将进入老年代”、“动态对象年龄判定”。
对象每“熬过”一次Minor GC,年龄加1。从Eden到Survivor时,年龄为1,之后的每一次都加1。
经测试,该策略在PS/Par Old下不存在。
示例3:空间分配担保
在GC时,发现Survivor区还无法容纳下所有的对象,就需要老年代进行担保,将Survivor无法容纳的对象直接存入老年代。
在担保前,会取之前每一次晋升到老年代容量的均值作为经验值,与老年代比较看是否需要Full GC。
经测试,该策略在PS/Par Old下不存在。
网友评论