pandening
11/1/2018 - 3:25 PM

测试JVM对象优先在Eden + From区域分配

测试JVM对象优先在Eden + From区域分配

package org.hujian.jvm.gc;

import org.hujian.common.JVMMemoryUnit;
import org.hujian.common.JvmTestRunner;

/**
 * Created on 2018/11/1 22:05.
 *
 * 
 */
public class TestEdenFirstAllocation extends JvmTestRunner {

    /**
     * 在这里实现测试逻辑,不提供参数列表以及返回值,执行该方法应该测试到
     * 你需要实现的所有逻辑,本方法单线程执行(main)
     */
    protected void execute() {
        /**
         * 测试点:
         *
         * 1、对象将优先在Eden里面进行分配,如果Eden区域没用足够空间进行分配时,JVM将
         *    进行一次"Minor GC",也就是所谓的"Young GC"
         * 2、"-XX:+PrintGCDetails"这个参数用于告诉JVM在发生GC的时候将内存回收日志
         *    打印出来,便于分析GC行为
         * 3、-Xms:20M  初始堆大小(初始堆大小 == 最大堆大小,代表堆不可扩展)
         *    -Xmx:20M  最大堆大小
         *    -Xms:128K 线程堆栈大小
         *    -Xmn:10M  新生代大小
         *    -XX:SurvivorRatio: 8 (代表Eden:s0:s1 = 8:1:1)
         * 
         *  JVM Arg: -XX:+UseConcMarkSweepGC -verbose:gc -XX:+PrintGCDetails -Xms20m -Xmx20m -Xmn10m -XX:SurvivorRatio=8
         */
        byte[] data1, data2, data3, data4;

        /// 堆大小总共20M,新生代10M,老年代10M
        /// Eden : s0: s1 = 8:1:1,所以Eden大小为1024 * (8/10) = 8192; s0 = s1 = 1024
        /// 所以Young区可以分配的空间大小为 Eden + s0 = 8192 + 1024 = 9216
        /// data1 - data3:  在Eden区域可以正常分配,占用大小为6M = 1024 * 6 = 6144
        /// data4请求分配4M大小的内存,但是Young区已经没有4M空间了,那么就只能进行一次"Minor GC"来清理Young区了

        data1 = JVMMemoryUnit.MB.alloc(2);
        data2 = JVMMemoryUnit.MB.alloc(2);
        data3 = JVMMemoryUnit.MB.alloc(2);
        data4 = JVMMemoryUnit.MB.alloc(4);

        // 防止优化没了
        System.out.println(data1[0] + data2[0] + data3[0] + data4[0]);

        /// [GC (Allocation Failure)
        //    [DefNew: 8186K->408K(9216K), 0.0105397 secs]
        //              8186K->6552K(19456K), 0.0106103 secs]
        // [Times: user=0.01 sys=0.00, real=0.01 secs]
        // 日志解读:首先说明了GC的原因是"Allocation Failure",然后DefNew则说明了GC发生的
        // 堆区域,8186K->408K(9216K)中,8186K是GC前该区域使用量,408k代表GC后该区域使用量
        // 括号内的9216k代表该区域的总大小;括号外的0.0105397 secs代表该区域的GC花费时间,之后的
        // 8186K->6552K(19456K),表示堆区域GC前使用量,GC之后使用量以及堆大小

        /// 这次GC发生的原因是在给data4分配内存的时候,发现Young区已没有4M空间提供分配了,所以需要进行
        /// 一次Minor GC来回收垃圾,但是GC之后发现data1-data3都还存活着,那只能将这些存活的对象复制
        /// 到S1中去(to区域),但是发现S1中内存不足以容纳任何大于1M的对象,所以JVM只好通过"分配担保"
        /// 机制将这些对象提前转移到老年代中去
    }

    public static void main(String[] args) {
        new TestEdenFirstAllocation().execute();
    }
}