大对象直接进入老年代
所谓大对象是指,需要大量连续内存空间的Java对象,是典型的大对象就是那种很长的字符串以及数组(例:byte[] allocation1, allocation2, allocation3, allocation4,这就是典型的大对象)。大对象对虚拟机的内存分配来说就是一个坏消息(替Java虚拟机抱怨一句,比遇到一个大对象更加坏的消息就是遇到一群“朝生夕灭”的“短命大对象”,写程序的时候应当避免),经常出现大对象容易导致内存还有不少空间时就提前触发垃圾收集以获取足够的连续空间“安置”它们。
虚拟机提供了一个-XX.PretenureSizeThreshold参数,令大于这个设置值的独享直接在老年代分配。这样做的目的是避免在Eden区及两个Survivor区之间发生大量的内存复制(复习一下:新生代采用复制算法收集内存)。
执行代码清单1-1中的testPretenureSizeThreshold()方法后,我们看到Eden空间几乎没有被使用,而老年代的10MB空间被使用了40%,也就是4MB的allocation对象直接就分配在老年代中,这是因为PretenureSizeThreshold被设置为3MB(就是3145728,这个参数不能像-Xmx之类的参数一样直接写3MB),因为超过3MB的对象都会直接在老年代进行分配。
注意:PretenureSizeThreshold参数只对Serial和ParNew两款收集器有效,Parallel Scavenge收集器不认识这个参数,Parallel Scavenge一般不需要设置。如果遇到必须使用此参数的场合,可以考虑ParNew加CMS的收集器组合。
代码清单1-1 大对象直接进入老年代
private static final int _1MB = 1024 * 1024;
/**
* VM参数:-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:SurvivorRatio=8
* -XX:PretenureSizeThreshold=3145728
*/
public static void testPretenureSizeThreshold() {
byte[] allocation;
allocation = new byte[4 * _1MB]; //直接分配在老年代中
}
}
运行结果:
Heap
def new generation total 9216K, used 671K
[0x029d0000, 0x033d0000, 0x033d0000)
eden space 8192K, 8% used [0x029d0000,
0x02a77e98, 0x031d0000)
from space 1024K, 0% used [0x031d0000, 0x031d0000, 0x032d0000)
to space 1024K, 0% used [0x032d0000, 0x032d0000, 0x033d0000)
tenured generation total 10240K, used 4096K
[0x033d0000, 0x03dd0000, 0x03dd0000)
the space 10240K, 40% used [0x033d0000,
0x037d0010, 0x037d0200, 0x03dd0000)
compacting perm gen total 12288K, used 2107K
[0x03dd0000, 0x049d0000, 0x07dd0000)
the space 12288K, 17% used [0x03dd0000,
0x03fdefd0, 0x03fdf000, 0x049d0000)
No shared spaces configured.