实验: 动态对象年龄判定

理论

正常情况下, 年轻代空间里边的对象熬过 MaxTernuringThreshold 才能晋升到老年代;但是如果 survivor 空间中
年龄1 + 年龄2 +年龄3 +…. + 年龄n (n>1)的这些对象大小的总和大于 survivor 空间的一半, 年龄大于或等于该年龄 n 的对象就会直接进入到老年代,不需要熬过那么多年龄

实验代码

public class DynamicAgeTest {
    private static Integer _1MB = 1024 * 1024;

    /**
     * jvm参数:
     * -verbose:gc -XX:+UseSerialGC -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=15 
     * @param args
     */
    public static void main(String[] args) {
        byte[] a1, a2, a3, a4, a5, a6;

        a1 = new byte[_1MB / 4];
	    //先造成一次minorgc,让a1的年龄加一
        a2 = new byte[_1MB * 4];
        a3 = new byte[_1MB * 4];

        // a1 + a4 等于 survivor区一半
        a4 = new byte[_1MB / 4];
	    //第二次minorgc,a1年龄=2,a4年龄=1
        a5 = new byte[_1MB * 4];
    }
}

gc日志

第一次gc
[GC (Allocation Failure) [DefNew:6177K->854K(9216K), 0.0047311 secs] 6177K->4950K(19456K), 0.0047783 secs] [Times: user=0.00 sys=0.01, real=0.01 secs]

第二次gc
[GC (Allocation Failure) [DefNew: 5447K->256K(9216K), 0.0041957 secs] 9543K->9299K(19456K), 0.0042255 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
Heap
def new generation total 9216K, used 4654K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
eden space 8192K, 53% used [0x00000000fec00000, 0x00000000ff04b6e0, 0x00000000ff400000)
from space 1024K, 25% used [0x00000000ff400000, 0x00000000ff440330, 0x00000000ff500000)
to space 1024K, 0% used [0x00000000ff500000, 0x00000000ff500000, 0x00000000ff600000)
tenured generation total 10240K,used 9043K[0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
the space 10240K, 88% used [0x00000000ff600000, 0x00000000ffed4c08, 0x00000000ffed4e00, 0x0000000100000000)
Metaspace used 3198K, capacity 4496K, committed 4864K, reserved 1056768K
class space used 346K, capacity 388K, committed 512K, reserved 1048576K

执行过程分析

当创建a3=4m 的时候,eden放不下,需要先进行一次 minor gc,a1进入survivor 年龄+1, 但是由于a2=4m > survivor=1m 只能进入老年代,然后才能把 a3放入eden区,minor gc后内存分布如下:
image

接着创建对象 a4,内存分布:
image

当创建对象 a5=4m的时候, eden空余空间 8m-a3(4m) - a4(0.25m)=3.75m 不够了,需要先进行minor gc,gc后内存分布如下
image
这时候年轻代里边应该是有 a1+a4= 0.5m,为survivor的一半,但是gc日志里边雀显示from区只占用了25%,老年代 used 9043K 又大于 a2(4m) + a3(4m)= 8m,说明是a1或者a4跑到老年代了

结合开头的理论 a1(年龄=2) + a4(年龄=1) 占用的空间等于survivor 的一半了,所以年龄n=2以及大于2的对象即a1需要晋升到老年代,最终内存分布如下
image

最终实验结果是和理论匹配的

posted @ 2021-03-16 23:06  mushishi  阅读(910)  评论(0编辑  收藏  举报