理解下栈上分配机制

本文探讨了Java对象分配的优化策略,包括逃逸分析和栈上分配。通过逃逸分析判断对象是否局限于方法内部,若对象无法逃逸,则可能在栈上分配,以提高性能。标量替换则是将对象拆分为基本类型,直接存储于栈中。通过调整JVM参数可以开启或关闭这些优化。然而,栈上分配受限于栈内存大小和对象大小,过大或无法逃逸的对象仍会存储在堆中。
摘要由CSDN通过智能技术生成

我们一般认为Java中创建的对象是放到堆里面的,但Java为了达到更高的性能要求,在高版本(此处指JDK8)中,有时会将对象直接生成在栈里面,比如我们常说的栈上分配。

我们都知道堆里面的对象回收,是需要等垃圾收集器处理的,但栈中的对象是随着方法调用结束而自行销毁,这样能达到更快释放的效果。那么栈上分配是怎样实现的呢?这里要说到两种机制:

一,逃逸分析
既然是逃逸,首先得有个“牢房”,在这里可以把每个方法当成一个“牢房”,每一个方法里的对象就是“囚犯”,那怎样逃呢?

当我们return 对象返回上级方法,或者是一个静态变量或常量,这样的对象在方法中就困不住,就会逃出去。那这种对象无法控制在方法内进行销毁,我们就称他们可以逃逸,反之则逃逸失败。

在JDK中逃逸分析默认是开启的,也可以使用JV参数关闭:

-XX:+DoEscapeAnalysis  //开启
-XX:-DoEscapeAnalysis  //关闭

我们可以思考下,无法逃逸的对象是不是就可以分配到栈上面随着栈的销毁而直接释放掉呢?

二,标量替换
标量是指无法再分解成更小粒度的数据,像数值类型。在 JIT 编译过程中,经过逃逸分析确定一个对象不会被其他线程或者方法访问,那么会将对象的创建替换成为多个成员变量的创建,称之为「标量替换」。
比如我们定义一个User类:

 class User{
        private String name;
        private Integer age;
       //省略getter和setter方法
        public User(String name, Integer age) {
            this.name = name;
            this.age = age;
        }
    }

当进行栈上分配时,不是将User对象存到栈中,而是将name和age分配进栈。
同样标量替换在JDK8中是默认开启的,也可以关闭:

-XX:+EliminateAllocations   //开启
-XX:-EliminateAllocations  //关闭

三,测试一下

  void test(){
        for(int i = 1;i<10000000;i++){
            new User("先生"+1,i);
        }
    }

    public static void main(String[] args) {
            new Test().test();
    }
//关闭逃逸分析和标题替换,将堆内存设为15M,因为创建的对象会直接放进堆中,所以会发生大量Full GC
-server -Xmx15m -Xms15m -XX:-DoEscapeAnalysis -XX:+PrintGC -XX:-EliminateAllocations

在这里插入图片描述

总结:栈上分配机制虽然能提升性能,但不是所有的对象都可以这样进行分配,它受制于我们栈内存的大小和我们创建的对象的大小,如果栈内存不足或对象过大,那还是老实老实存入堆里面吧。我是阿雷,一个划水多年的程序员。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值