JVM基础到实战06-jvm内存自动分配原则

一、java堆的基本分配规则

1.
-对象主要分配在新生代的Eden区
-如果启动了本地线程分配缓冲,按线程优先在TLAB上分配
-少数情况下也可能直接分配在老年代中,比如较大的对象

2.GC参数指定垃圾回收
-Xms20M   jvm初始内存
-Xmx20M   jvm最大内存
-Xmn10M   jvm年轻代大小
这三个参数限制了java堆大小为20MB不可拓展,其中10MB
分配给新生代,剩下的10MB分配给老年代,一般我们将新生代老年代比列设置为为1:2
-Xx:SurvivorRatio=8决定了新生代中Eden区与两个Survivor区的
空间比例为8:1

JVM基础到实战06-jvm内存自动分配原则_第1张图片

3.
新生代GC(MinorGC) :发生在新生代的GC
老年代GC(MajorGC或者FullGC)
一般情况下,MajorGC比FullGC慢10倍以上

测试代码:

/**
 * @Auther: jorian
 * @Date: 2019/7/31 21:16
 * @Description:
 */
public class JvmTest01 {
    private static final int bsize = 1024*1024;
    public static void main(String []args){
        byte[] b =new byte[40*bsize];
    }
}

配置启动参数: -verbose:gc -XX:+PrintGCDetails

JVM基础到实战06-jvm内存自动分配原则_第2张图片

可以看到使用的parllel scavenge的垃圾收集器

JVM基础到实战06-jvm内存自动分配原则_第3张图片
我们也可以指定使用串行的serial垃圾收集器: -verbose:gc -XX:+PrintGCDetails -XX:+UseSerialGC

JVM基础到实战06-jvm内存自动分配原则_第4张图片

可以看到,垃圾收集器已被修改,def就是指serial垃圾收集器

JVM基础到实战06-jvm内存自动分配原则_第5张图片

结论:基本分配原则:对象初始分配一般在新生代的Eden区

二、大对象的分配规则

-所谓的大对象是指需要大量连续内存空间的java对象,最典型的大对象就是那种很长的字符串
以及数组
-虚拟机提供了一个-XX:PretennureSizeThreshold参数,令大于这个设置值的对象直接在老年代分配
这样避免了在新生代的Eden和Survivor区发生较大的内存复制

代码测试:

/**
 * @Auther: jorian
 * @Date: 2019/7/31 21:53
 * @Description:
 */
public class JvmTest02 {

    public static void main(String args[]){
       byte[] bytes = new byte[1024*1024*10];//10M
    }
}

设置启动参数:
-verbose:gc                           //开启GC日志
-XX:+PrintGCDetails             //打印GC详情
-XX:+UseSerialGC                 //使用SerialGC
-XX:PretenureSizeThreshold=314728   //设置大对象阈值,超过即分配到老年代
-Xms20M   -Xms20M  -Xmx20M  -Xmn10M
 

JVM基础到实战06-jvm内存自动分配原则_第6张图片

启动项目,结果:可以看到,老年代正好占用了10M,说明超过我们设置的3M阈值,对象分配到了老年代

JVM基础到实战06-jvm内存自动分配原则_第7张图片

三、逃逸分析和栈上分配

逃逸分析:
逃逸分析的基本行为就是分析对象的动态作用域,当一个对象在方法中被定义后,它可能被外部方法所引用
,称为方法逃逸,甚至还有可能被外部线程访问到,比如赋值给类变量或可以在其他线程中访问的实例变量
,称为线程逃逸

栈上分配:
栈上分配就是把方法中的变量和对象分配到栈上,方法执行完后自动销毁,而且不需要垃圾回收的介入
从而提高系统性能。

栈上分配演练:代码:

/**
 * @Auther: jorian
 * @Date: 2019/7/31 22:18
 * @Description:
 */
public class TestEscape {

    public static Object obj;
    public void variableEscape(){
        obj = new Object();  //发生逃逸
    }

    public Object methodEscape(){
        return new Object();//方法逃逸,不在方法里面了
    }

    public static void alloc(){
        byte[] bytes = new byte[2];
        bytes[0] = 1;
    }

    public static void main(String args[]){
        Long start = System.currentTimeMillis();
       //分配1000万次
        for(int i = 0; i < 100000000; i++){
            alloc();
        }
        Long end = System.currentTimeMillis();
        System.out.println(end-start);
    }

}

设置jvm启动参数,关闭jdk1.8默认开启的逃逸分析:-XX:-DoEscapeAnalysis

JVM基础到实战06-jvm内存自动分配原则_第8张图片

启动程序:可以看到时间为47

JVM基础到实战06-jvm内存自动分配原则_第9张图片

修改jvm启动参数,加上逃逸分析,-XX:+DoEscapeAnalysis

JVM基础到实战06-jvm内存自动分配原则_第10张图片

可以看到时间大幅缩小,时间为:15

JVM基础到实战06-jvm内存自动分配原则_第11张图片

如果开启了逃逸分析,就会进行栈上分配。
关闭逃逸分析,打开gc日志:

JVM基础到实战06-jvm内存自动分配原则_第12张图片

启动程序,发生了频繁的yongGC!!原因是内存不够分配。 

JVM基础到实战06-jvm内存自动分配原则_第13张图片

 

 

 

 

你可能感兴趣的:(JVM,jvm,java,内存)