大对象是指需要大量连续内存空间的Java对象,如字符串以及数组。虚拟机提供参数-XX:PretenureSizeThreshold参数来指定大对象,大于该值的对象都是大对象。如下我们指定大于3M的对象都是大对象,可以从打印日志中看出allocation3直接被分配到老年代中。程序如下:
public class Main { private static final int _1MB = 1024 * 1024; public static void main(String[] args) { /** * VM参数:-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:+UseSerialGC -XX:PretenureSizeThreshold=3145728 * -Xms20M 设置堆大小为20M -Xmx20M 避免堆自动扩展 -Xmn10M 设置年轻代大小 * -XX:+PrintGCDetails 打印日志信息 * -XX:SurvivorRatio=8 设置Eden和Survivor大小比值 * --XX:+UseSerialGC 使用Serial + Serial Old收集器组合进行内存回收 * -XX:PretenureSizeThreshold=3145728 指定超过3M的对象直接进入老年代 */ // TODO Auto-generated method stub byte[] allocation1, allocation2, allocation3, allocation4; allocation1 = new byte[1 * _1MB]; //allocation2 = new byte[2 * _1MB]; allocation3 = new byte[6 * _1MB]; //新生代需要Minor GC,Full GC //allocation4 = new byte[4 * _1MB]; } } //打印日志如下 Heap def new generation total 9216K, used 2024K [0x00000000f9a00000, 0x00000000fa400000, 0x00000000fa400000) eden space 8192K, 24% used [0x00000000f9a00000, 0x00000000f9bfa028, 0x00000000fa200000) from space 1024K, 0% used [0x00000000fa200000, 0x00000000fa200000, 0x00000000fa300000) to space 1024K, 0% used [0x00000000fa300000, 0x00000000fa300000, 0x00000000fa400000) tenured generation total 10240K, used 6144K [0x00000000fa400000, 0x00000000fae00000, 0x00000000fae00000) the space 10240K, 60% used [0x00000000fa400000, 0x00000000faa00010, 0x00000000faa00200, 0x00000000fae00000) compacting perm gen total 21248K, used 2558K [0x00000000fae00000, 0x00000000fc2c0000, 0x0000000100000000) the space 21248K, 12% used [0x00000000fae00000, 0x00000000fb07f9c8, 0x00000000fb07fa00, 0x00000000fc2c0000) No shared spaces configured.
长期存活的对象将进入老年代既然虚拟机采用了分代收集的思想来管理内存,那么内存回收时就必须能识别哪些对象应放在新生代,哪些对象应放在老年代。为了做到这一点,虚拟机给每个对象定义了一个对象年龄计数器。如果对象在Eden出生并经过第一次Minor GC后仍然存活且能被Survivor容纳的话,将被移动到Survivor空间,并且对象年龄设为1,对象在Survivor区中每经过一次Minor GC,年龄就增加1岁,当年龄增加到一定程度(默认是15岁),就会晋升到老年代。对象晋升到老年代的年龄阈值,可以通过参数-XX:MaxTenuringThreshold设置。还是看一段代码和日志信息吧!
public class Main {
private static final int _1MB = 1024 * 1024;
public static void main(String[] args) {
/**
* VM参数:-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=1 -XX:+PrintTenuringDistribution
* -Xms20M 设置堆大小为20M -Xmx20M 避免堆自动扩展
-Xmn10M 设置年轻代大小
* -XX:+PrintGCDetails 打印日志信息
* -XX:SurvivorRatio=8 设置Eden和Survivor大小比值
* -XX:MaxTenuringThreshold 当年龄大于该值时,放入老年代
*/
// TODO Auto-generated method stub
byte[] allocation1, allocation2, allocation3, allocation4;
allocation1 = new byte[_1MB / 4];
allocation2 = new byte[4 * _1MB];
allocation3 = new byte[5 * _1MB]; //新生代执行Minor GC,将allocation1移入Survivor,将allocation2移入老年代
allocation3 = null;
allocation3 = new byte[4 * _1MB]; //直接在新生代上分配空间
}
}
//打印日志信息
[GC[DefNew
Desired survivor size 524288 bytes, new threshold 1 (max 1)
- age 1:
737904 bytes,
737904 total
: 5188K->720K(9216K), 0.0044078 secs] 5188K->4816K(19456K), 0.0044833 secs] [Times: user=0.02 sys=0.00, real=0.02 secs]
[GC[DefNew
Desired survivor size 524288 bytes, new threshold 1 (max 1)
- age 1:
136 bytes,
136 total
: 5925K->0K(9216K), 0.0028463 secs] 10021K->4816K(19456K), 0.0029261 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
Heap
def new generation total 9216K, used 4260K [0x00000000f9a00000, 0x00000000fa400000, 0x00000000fa400000)
eden space 8192K, 52% used [0x00000000f9a00000, 0x00000000f9e28fd0, 0x00000000fa200000)
from space 1024K, 0% used [0x00000000fa200000, 0x00000000fa200088, 0x00000000fa300000)
to space 1024K, 0% used [0x00000000fa300000, 0x00000000fa300000, 0x00000000fa400000)
tenured generation total 10240K, used 4816K [0x00000000fa400000, 0x00000000fae00000, 0x00000000fae00000)
the space 10240K, 47% used [0x00000000fa400000, 0x00000000fa8b4050, 0x00000000fa8b4200, 0x00000000fae00000)
compacting perm gen total 21248K, used 2558K [0x00000000fae00000, 0x00000000fc2c0000, 0x0000000100000000)
the space 21248K, 12% used [0x00000000fae00000, 0x00000000fb07fa00, 0x00000000fb07fa00, 0x00000000fc2c0000)
No shared spaces configured.