Java故障诊断与性能优化-栈上分配

Laughing
2021-12-19 / 0 评论 / 836 阅读 / 正在检测是否收录...
温馨提示:
本文最后更新于2024年03月16日,已超过307天没有更新,若内容或图片失效,请留言反馈。

正常情况下,Java对象是存储到堆上的,为了优化系统性能,Java虚拟体提供了一种栈上分配的技术,栈上分配的基本思想是:对于那些线程私有的对象(不能被其他线程访问的对象),Java虚拟机将对象打散分配到栈上,而不是分配到堆上。
之所以分配到栈上,是因为在函数调用结束后,可以将对象信息自行销毁,而不需要垃圾回收器介入。
栈上分配技术基础是逃逸分析,逃逸分析的目的是检查对象的作用域是否有可能逃出函数体。

能够逃逸的对象

下面演示一个能够逃逸的对象,因为能够逃逸,所以是无法进行栈上分配的。

public class Test{

    public static class User{
        
        public String name;

        public int age;

        public User(String name,int age){
            this.name=name;
            this.age=age;
        }



    }

    public static User alloc(){
        User user = new User("Test",30);
        user.name = "张三";
        user.age=40;
        return user;
    }

    public static void main(String[] args) throws InterruptedException{
        long startTime = System.currentTimeMillis();
        User user = new User("Test",30);
        for(int i=0;i<100000000;i++){
            user=    alloc();
        }
        System.out.println(user.age);
        long endTime = System.currentTimeMillis();
        System.out.println(endTime - startTime);
    }
}

执行

java -server -Xmx20m -Xms20m -XX:+PrintGC Test

可以看到代码发生了大量的GC。

不能逃逸的对象

相同的代码,我们只是设置对象不能逃逸,进行一下改造。

public class Test{

    public static class User{
        
        public String name;

        public int age;

        public User(String name,int age){
            this.name=name;
            this.age=age;
        }



    }

    public static void alloc(){
        User user = new User("Test",30);
        user.name = "张三";
        user.age=40;
    }

    public static void main(String[] args) throws InterruptedException{
        long startTime = System.currentTimeMillis();
        for(int i=0;i<100000000;i++){
            alloc();
        }
        long endTime = System.currentTimeMillis();
        System.out.println(endTime - startTime);
    }
}

执行

java -server -Xmx20m -Xms20m -XX:+DoEscapeAnalysis -XX:+PrintGC -XX:-UseTLAB -XX:+EliminateAllocations Test

输出
可以看到并没有任何GC程序就执行完了。

参数说明

第二段启用逃逸分析时,我们参数明显是比第一段多了。
-server:Server模式下,才可以启用逃逸分析。
-XX:+DoEscapeAnalysis: 启用逃逸分析。
-XX:-UseTLAB:TLAB全称是Thread Local Allocation Buffer,也就是线程级别的内存分配,每个线程独享一块内存,主要是针对Eden里的一块小内存,这样线程在分配内存的时候,因为这块小内存是这个线程独享的,因此不会出现锁竞争的问题,默认是开启该功能的,不建议关闭此功能,主要是保证内存分配的高效性
-XX:+EliminateAllocations:开启标量替换(默认开启),运行将对象打散分配到栈上,比如我们上面User对象有idname两个字段,那么这两个字段将会被视为两个独立的局部变量进行分配。

0

评论 (0)

取消