内存分配与回收策略

    1.对象优先在Eden分配

        大多数情况下,对象在新生代Eden区中分配。当Eden区没有足够空间进行分配时,虚拟机将发起一次Minor GC。

        -XX:+PrintGCDetails:在发生垃圾收集行为时打印内存回收日志,并且在进程退出的时候输出当前的内存各区域分配情况。

        -XX:SurvivorRatio=8决定了新生代中Eden区与一个Survivor区的空间比例是8:1。

        新生代GC(Minor GC):发生在新生代的垃圾收集动作,因为Java对象大多都具备朝生夕灭的特性,所以Minor GC非常频繁,一般回收速度也非常快。

        老年代GC(Major GC/Full GC):指发生在老年代的GC,出现了Major GC经常会伴随至少一次Minor GC(非绝对,在Parallel Scavenge收集器的收集策略就有直接进行Major GC的策略选择过程)。Major GC速度一般会比Minor GC慢10倍以上。

    

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

        大对象:需要大量连续内存空间的Java对象,

        -XX:PretenureSizeThreshold:令大于这个设置值的对象直接在老年代分配。目的是避免在Eden区及两个Survivor区直接发生大量的内存复制(新生代采用复制算法收集内存)。该参数只对Serial和ParNew两款收集器有效。

    

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

        为了在内存回收时能区别哪些对象应放在新生代,哪些对象应放在老年代中,虚拟机给每个对象定义了一个对象年龄(Age)计数器。

        如果对象在Eden出生并经过第一次Minor GC后仍然存活,并且能被Survivor容纳的话,将被移动到Survivor空间中,并且对象年龄设为1。对象在Survivor区中每熬过一次Minor GC,年龄就增加1岁,当它的年龄增加到一定程度(默认为15岁),就将会被晋升到老年代中。对象晋升老年代的年龄阈值,可以通过参数-XX:MaxTenuringThreshold设置。


    4.动态对象年龄判断

        虚拟机并不是严格要求对象年龄必须达到MaxTenuringThreshold才能晋升老年代,如果子啊Survivor空间中相同年龄所有对象大小和总和大于Survivor空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代,无需等到MaxTenuringThreshold中要求的年龄。

    

    5.空间分配担保

        在发生Minor GC之前,虚拟机会先检查老年代最大可用的连续空间是否大于新生代所有对象总空间,如果该条件成立,则Minor GC可以确定是安全的。如果不成立,则虚拟机会查看HandlePromotionFailure设置值是否允许担保失败。如果允许,那么会检查老年代最大可用的连续空间是否大于历次晋升到老年代对象的平均大小,如果大于,将尝试进行一次Minor GC,尽管这次的Minor GC是有风险的;或者HandlePromotionFailure设置不允许冒险,那这时也要改为进行一次Full GC。

        新生代使用复制收集算法,为了内存利用率,只是用其中一个Survivor空间来作为轮换备份,因此当出现大量对象在Minor GC后仍然存活的情况,就需要兰年度进行分配担保,吧Survivor无法容纳的对象直接进入老年代。老年代要进行这样的担保,前提是老年代本身还有容纳这些对象的剩余空间。

        JDK1.6之后的规则变为只要老年代的连续空间大于新生代对象总大小或者历次晋升的平均大小就会进行Minor GC,否则将进行Full GC。HandlePromotionFailure参数不会再影响到虚拟机的空间分配担保策略。