内存分配与回收策略

        对象的分配通常就是指在堆上分配(也可能经过JIT编译后间接地在栈上分配),主要分配在新生代的Eden区,如果启动了本地线程分配缓冲将按线程优先在TLAB上分配,也可能直接分配在老年代,分配的规则取决于使用的垃圾收集器的组合及虚拟机内存相关参数的设置。

1、对象优先在Eden分配

        大多数对象在新生代Eden区中分配,Eden区空间不够时虚拟机将发起一次Minor GC。

2、大对象直接进入老年代

        设置虚拟机运行时参数-XX:PretenureSizeThreshold,使大于这个参数值的对象直接在老年代分配,避免在新生代(采用复制算法收集内存)的Eden区和两个Survivor区发生大量内存复制。

3、长期存活的对象进入老年代

        在内存回收时为了能够识别哪些对象应放在新生代、哪些对象应放在老年代,虚拟机为每个对象定义了一个对象年龄计数器。对象如果在Eden出生,经过一次Minor GC后仍然存活并能被Survivor区容纳,将被移动到Survivor区且对象年龄设为1。对象在Survivor区中每熬过一次Minor GC,年龄就增加1岁,当年龄增加到年龄阈值(通过-XX:MaxTenuringThreshold设置,默认为15岁),对象就晋升到老年代中。

4、动态对象年龄判定

        如果在Survivor区中相同年龄所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代,无须等到-XX:MaxTenuringThreshold参数设置的年龄。

5、空间分配担保

        发生Minor GC之前,虚拟机会检查老年代中的最大可用连续空间是否大于新生代中所有对象的总空间,若条件成立,进行Minor GC。若不成立,虚拟机会查看-XX:+HandlePromotionFailure参数设置的值是否允许担保失败。如果允许,检查老年代中的最大可用连续空间是否大于历次晋升到老年代对象的平均大小,若大于,进行Minor GC;若小于或者-XX:+HandlePromotionFailure参数设置的值不允许担保失败,则进行一次Full GC。

        JDK6之后,-XX:MaxTenuringThreshold参数不再影响空间分配担保策略,规则变为只要老年代中的最大可用连续空间大于新生代中所有对象的总空间或者历次晋升到老年代对象的平均大小就进行Minor GC,否则进行Full GC。

        指定JVM运行时参数-Xms20M、-Xmx20M、-Xmn10M、-XX:SurvivorRatio=8,则java堆大小为20M,不可扩展,新生代大小为10M,新生代中Eden与Survivor区的比例为8:1,则老年代大小为(20-10)M,新生代中Eden区大小为8/(8+1+1)M,两个Survivor区大小均为1/(8+1+1)M,新生代总可用空间为(8+1)/(8+1+1)M。

public class MinorGCTest {
    private static final int _1MB = 1024 * 1024;

    /**
     VM参数:-verbose:gc -Xms20m -Xmx20m -Xmn10m -XX:+PrintGCDetails -XX:SurvivorRatio=8
     */
    public static void main(String[] args) {
        byte[] allocation1 = new byte[2 * _1MB];
        byte[] allocation2 = new byte[2 * _1MB];
        byte[] allocation3 = new byte[2 * _1MB];
    }
}

        上述代码的执行结果如下所示:

Heap
 PSYoungGen      total 9216K, used 8050K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
  eden space 8192K, 98% used [0x00000000ff600000,0x00000000ffddca40,0x00000000ffe00000)
  from space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
  to   space 1024K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x00000000fff00000)
 ParOldGen       total 10240K, used 0K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
  object space 10240K, 0% used [0x00000000fec00000,0x00000000fec00000,0x00000000ff600000)
 Metaspace       used 3425K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 328K, capacity 388K, committed 512K, reserved 1048576K

         程序执行后,Eden区被占用98%,Survivor区空闲,老年代空闲,继续添加并执行执行分配allocacation4对象的语句。

public class MinorGCTest {
    private static final int _1MB = 1024 * 1024;

    /**
     VM参数:-verbose:gc -Xms20m -Xmx20m -Xmn10m -XX:+PrintGCDetails -XX:SurvivorRatio=8
     */
    public static void main(String[] args) {
        byte[] allocation1 = new byte[2 * _1MB];
        byte[] allocation2 = new byte[2 * _1MB];
        byte[] allocation3 = new byte[2 * _1MB];
        byte[] allocation4 = new byte[2 * _1MB];// 出现一次Minor GC
    }
}

        结果如下:

[GC (Allocation Failure) [PSYoungGen: 7886K->448K(9216K)] 7886K->6592K(19456K), 0.0146869 secs] [Times: user=0.01 sys=0.00, real=0.01 secs] 
[Full GC (Ergonomics) [PSYoungGen: 448K->0K(9216K)] [ParOldGen: 6144K->6501K(10240K)] 6592K->6501K(19456K), [Metaspace: 3417K->3417K(1056768K)], 0.0238688 secs] [Times: user=0.03 sys=0.00, real=0.03 secs] 
Heap
 PSYoungGen      total 9216K, used 2130K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
  eden space 8192K, 26% used [0x00000000ff600000,0x00000000ff814930,0x00000000ffe00000)
  from space 1024K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x00000000fff00000)
  to   space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
 ParOldGen       total 10240K, used 6501K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
  object space 10240K, 63% used [0x00000000fec00000,0x00000000ff259620,0x00000000ff600000)
 Metaspace       used 3424K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 328K, capacity 388K, committed 512K, reserved 1048576K

        执行分配allocacation4对象的语句时会发生一次Minor GC,原因是Eden区剩余空间不足以分配allocacation4所需的空间。GC的结果是新生代从7886K变为448K,总内存从7886K变为6592K,因为已有的三个对象都是存活的,且都无法放入Survivor区,只好通过分配担保机制提前转移到老年代。GC结束后,Enden区被占用2MB(allocacation4对象),Survivor区空闲,老年代被占用6MB(allocacation1、allocacation2、allocacation3对象)。

         

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值