1. 对象优先分配在Eden区
当Eden区没有足够的内存空间时,发起一次Monitor GC。
private static final int M= 1024 * 1024;
public static void main(String[] arg) {
byte[] a1 = new byte[2 * M];
byte[] a2 = new byte[2 * M];
byte[] a3 = new byte[2 * M];
byte[] a4 = new byte[4 * M];
}
[GC [DefNew: 6487K->148K(9216K), 0.0094068 secs] 6487K->6293K(19456K), 0.0094970 secs] [Times: user=0.02 sys=0.00, real=0.01 secs]
Heap
def new generation total 9216K, used 4408K [0x315e0000, 0x31fe0000, 0x31fe0000)
eden space 8192K, 52% used [0x315e0000, 0x31a08fe0, 0x31de0000)
from space 1024K, 14% used [0x31ee0000, 0x31f053f0, 0x31fe0000)
to space 1024K, 0% used [0x31de0000, 0x31de0000, 0x31ee0000)
tenured generation total 10240K, used 6144K [0x31fe0000, 0x329e0000, 0x329e0000)
the space 10240K, 60% used [0x31fe0000, 0x325e0030, 0x325e0200, 0x329e0000)
compacting perm gen total 12288K, used 378K [0x329e0000, 0x335e0000, 0x369e0000)
the space 12288K, 3% used [0x329e0000, 0x32a3e920, 0x32a3ea00, 0x335e0000)
ro space 10240K, 54% used [0x369e0000, 0x36f5e4a8, 0x36f5e600, 0x373e0000)
rw space 12288K, 55% used [0x373e0000, 0x37a822a0, 0x37a82400, 0x37fe0000)
2. 大对象直接进入老年代。
虚拟机提供了一个参数:-XX:PretenureSizeThreshold,用来设定大对象直接分配到老年代。这个参数只对Serial和ParNew有效。
public static void main() {
byte[] a4 = new byte[4 * M];
}
Heap
def new generation total 9216K, used 507K [0x315e0000, 0x31fe0000, 0x31fe0000)
eden space 8192K, 6% used [0x315e0000, 0x3165ef38, 0x31de0000)
from space 1024K, 0% used [0x31de0000, 0x31de0000, 0x31ee0000)
to space 1024K, 0% used [0x31ee0000, 0x31ee0000, 0x31fe0000)
tenured generation total 10240K, used 4096K [0x31fe0000, 0x329e0000, 0x329e0000)
the space 10240K, 40% used [0x31fe0000, 0x323e0010, 0x323e0200, 0x329e0000)
compacting perm gen total 12288K, used 378K [0x329e0000, 0x335e0000, 0x369e0000)
the space 12288K, 3% used [0x329e0000, 0x32a3e9f8, 0x32a3ea00, 0x335e0000)
ro space 10240K, 54% used [0x369e0000, 0x36f5e4a8, 0x36f5e600, 0x373e0000)
rw space 12288K, 55% used [0x373e0000, 0x37a822a0, 0x37a82400, 0x37fe0000)
3. 长期存活的对象将进入老年代
可以通过参数:-XX:MaxTenuringThreshold设置。
public static void main() {
byte[] a1 = new byte[M / 4];
byte[] a2 = new byte[4 * M];
byte[] a3 = new byte[4 * M];
byte[] a3 = null;
byte[] a3 = new byte[4 * M];
}
[GC [Tenured: 8192K->4501K(10240K), 0.3121115 secs] 8791K->4501K(19456K), [Perm : 378K->378K(12288K)], 0.3121796 secs] [Times: user=0.02 sys=0.01, real=0.31 secs]
Heap
def new generation total 9216K, used 327K [0x315e0000, 0x31fe0000, 0x31fe0000)
eden space 8192K, 4% used [0x315e0000, 0x31631f98, 0x31de0000)
from space 1024K, 0% used [0x31de0000, 0x31de0000, 0x31ee0000)
to space 1024K, 0% used [0x31ee0000, 0x31ee0000, 0x31fe0000)
tenured generation total 10240K, used 8597K [0x31fe0000, 0x329e0000, 0x329e0000)
the space 10240K, 83% used [0x31fe0000, 0x32845420, 0x32845600, 0x329e0000)
compacting perm gen total 12288K, used 378K [0x329e0000, 0x335e0000, 0x369e0000)
the space 12288K, 3% used [0x329e0000, 0x32a3eaf8, 0x32a3ec00, 0x335e0000)
ro space 10240K, 54% used [0x369e0000, 0x36f5e4a8, 0x36f5e600, 0x373e0000)
rw space 12288K, 55% used [0x373e0000, 0x37a822a0, 0x37a82400, 0x37fe0000)
参数值为:1时。
参数值为:15时。
4.动态对象年龄判断
如果Survivor中相同年龄的对象占到此空间的一半,那么改年龄和大于该年龄的对象放到老年区。
5. 空间分配担保
在发生Minor GC时,会计算每次进入老年区的平均大小是否大于老年区空间的剩余大小,如果大于则进行一次Full GC。
对象分配规则
1.对象优先分配在Eden区,如果Eden区没有足够的空间时,虚拟机执行一次Minor GC。
2.大对象直接进入老年代(大对象是指需要大量连续内存空间的对象)。这样做的目的是避免在Eden区和两个Survivor区之间发生大量的内存拷贝(新生代采用复制算法收集内存)。
3.长期存活的对象进入老年代。虚拟机为每个对象定义了一个年龄计数器,如果对象经过了1次Minor GC那么对象会进入Survivor区,之后每经过一次Minor GC那么对象的年龄加1,知道达到阀值对象进入老年区。
4.动态判断对象的年龄。如果Survivor区中相同年龄的所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象可以直接进入老年代。
5.空间分配担保。每次进行Minor GC时,JVM会计算Survivor区移至老年区的对象的平均大小,如果这个值大于老年区的剩余值大小则进行一次Full GC,如果小于检查HandlePromotionFailure设置,如果true则只进行Monitor GC,如果false则进行Full GC。