垃圾回收机制的实验记录

来源:互联网 发布:fd软件下载 编辑:程序博客网 时间:2024/05/01 23:00
  Java虚拟机创建的时候,可通过参数-Xms设置堆空间的最大值,-Xmx设置堆空间的最大值,默认的情况下堆空间的最小值为物理内存的1/64但小于1G,最大值默认为物理内存的1/4但小于1G。默认的情况下,当空余的内存小于40%,虚拟机会增加堆大小到-Xmx的指定大小,空余空间大于70%,虚拟机会减少堆内存到-Xms的指定大小。而一般为了避免堆内存的频繁改变大小,通常-Xms和-Xmx设置为同一个值。
  堆中的新生代和老年代的默认比值为:2:1,新生代中的Eden与Surivivor比值默认为8:2,Surivivor的From和To大小一样。(为什么From和To空间大小要一样,那是因为From和To可进行角色互换,在进行垃圾回收的过程中,From和Eden上的存活对象复制到To空间上,而在To空间上对象是按顺序存放的,From和Eden上的所以对象回收后,新生代中不存在空间碎片,而下一次,From就变成了To,To则变成了From),而新生代一般比老年代要小,是因为新生代中的对象98%是“朝生夕死”的,而且Minor GC比Full GC快10倍以上。所以一般都是老年代比新生代大。


      private static final int _1MB = 1024*1024;

    /**
    *VM 参数:-verbose:gc-Xms20M-Xmx20M-Xmn10M-XX:+PrintGCDetails
    *年轻代10M,测试当年轻代不足时,对象没到默认的15年龄就进入老年代
    */
    public static void test1()
    {
        byte[] a, b, c, d;
        a= new byte[2 * _1MB];
        b= new byte[2 * _1MB];
        c= new byte[2 * _1MB];
        d= new byte[4 * _1MB];//进行一次Minor GC
    }
Window上的Java虚拟机默认的收集器是PS收集器,所以会动态改变Eden与Surivivor的比值,因此上述的结果为,Eden空间用了87%,而老年代的空间用了40%,也就是a和b对象进入了老年代,而c、d对象则在新生代中。
而强制使用Serial 收集器,则是老年代空间占用了60%,a、b、c对象都进入了老年代。而d对象在新生代中。

    /**
    *VM 参数:-verbose:gc -Mxs20M -Xmx20M -Xmn10M -XX:+PrintGCDetails 
    *    -XX:SurvivorRatio=8 -XX:PretenureSizeThreshold=3145728
    *设置大于3M的对象直接进入老年代,3M(就是3145728)
    */
    public static void test2()
    {
        byte[] allocation;
        allocation = new byte[5*_1MB];
    }

因为Window上默认的是PS收集器,所以,这5M分配到新生代中。
而使用Serial 收集器则是分配到老年代中。


/*
*VM参数:-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 
*-XX:MaxTenuringThreshold=1 -XX:+PrintTenuringDistribution
*测试年龄大于1的对象进入老年代
*/

    public static void test3()
    {
        byte[] a, b, c;
        a = new byte[_1MB / 4];
        b = new byte[4 * _1MB];
        c = new byte[4 * _1MB];
        c = null;
        c = new byte[4 * _1MB];//空间不足,进行MinorGC
    }
这个不管设置成1还是15,结果都是一样的,我觉得原因应该是,当进行GC的时候,Eden中存活的对象a和b要复制到To 空间中,由于To空间不足,所以直接进入老年代。老年代空间用了47%,也就是a和b对象都进入了老年代。


/*
*VM参数: -verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 
*-XX:MaxTenuringThreshold=15 -XX:+PrintTenuringDistribution
*动态对象年龄判定
*/

    public static void test4()
    {
        byte[] a, b, c, d;
        a = new byte[_1MB / 4];
        b = new byte[_1MB / 4];//a+b大于surivivor空间的一半
        c = new byte[_1MB * 4];
        d = new byte[_1MB * 4];//设置为5M,还是4M,都是进行了GC。
        //这难道是JDK1.7之后的优化????
    }

当进行GC的时候,a,b幸存对象To空间,c直接进入老年代。所以老年代空间占用刚好40%,而并没有按照大于Surivivor空间一半时,进入老年代。

/*
*VM 参数:-Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 
*-XX:-HandlePromotionFailure=true/false(失效了)
*测试空间分配担保
*/
public static void test5()
{
    byte[] a, b, c, d, e, f, g;
    a = new byte[2 * _1MB];
    b = new byte[2 * _1MB];
    c = new byte[2 * _1MB];
    a = null;
    d = new byte[2 * _1MB];
    e = new byte[2 * _1MB];//空间不足,进行GC,b,c,d进入老年代
     f = new byte[2 * _1MB];
    d = null;
    e = null;
    f = null;
    g = new byte[2 * _1MB];
}
在JDK1.6之后,空间担保机制失效了,改成了只要老年代的连续空间大于新生代的对象总大小或者历次晋升老年代的平均大小,则进行MinorGC,否则进行FullGC
当进行第一次GC的时候,老年代中有bcd三个对象,总共6M。当执行到了new g对象之后,新生代总共用了6M,而老年代中剩余大小4M,不应该进行GC,而虚拟机进行了两次的Minor GC,两次GC都是在新生代内存用了大概75%之后进行的GC,这应该是JDK1.7之后的优化。
0 0
原创粉丝点击