深入浅出逃逸分析:提升程序性能的利器

开发
逃逸分析技术是JVM用于提高性能以及节省内存的手段,在JVM编译语境下也就是我们常说的JIT阶段,那么我们又该如何判断对象是否逃逸呢?

逃逸分析技术算是在JVM面试题偶有提及的一个考察点,当然如果你能够讲解JVM工作原理的时候提及这一点,这一定会增加面试官对你的好感,本文主题内容如下:

  • 什么是逃逸分析技术?
  • 逃逸分析技术解决什么问题?带来什么好处?
  • 如何更好的理解或者运用逃逸分析技术?

一、什么是逃逸分析

逃逸分析技术是JVM用于提高性能以及节省内存的手段,在JVM编译语境下也就是我们常说的JIT阶段,逃逸分析技术通过以下两个条件判断该对象是否是逃逸:

  • 该对象是否分配在堆上(static关键字或者成员变量)。
  • 该对象是否会传给未知代码,比如return到外部给别的类使用。

只要编译阶段判定当前对象并没有发生逃逸,那么它就会采用栈上分配、标量替换、同步锁消除等手段提升程序执行性能和节省内存开销。

那么我们又该如何判断对象是否逃逸呢?我们不妨基于上述的判断条件来看看这个示例,假设我们现在有一个user类:

@Data
public class User {

    private int id;

    private String name;
}

我们通过UserService进行初始化,那么请问这段代码是否发生逃逸呢?

public class UserService {

    private User user;

    public void init() {
        user = new User();
        user.setId(RandomUtil.randomInt(10));
        user.setName(RandomUtil.randomString(3));
    }
}

答案当然是肯定的,因为这段代码会被外部的其他任意线程操作。

再来看看这段代码,典型的return语句,很明显的外部线程可以直接操作这个对象,所以这个对象也发生了逃逸,所以针对这几种情况JIT都无法对其进行优化。

public User createUser() {
        User user = new User();
        user.setId(RandomUtil.randomInt(10));
        user.setName(RandomUtil.randomString(3));
        return user;
    }

二、如何运用到逃逸分析技术

1.栈上分配

一般来说,JIT即时编译技术中的栈上分配和标量替换基本都是同时出现的,按照上文所述,假如上述代码所返回的user对象仅仅是获取当前用户的年龄,那么我们就可以直接在方法内完成逻辑计算并直接返回,这样对象就没有发生逃逸,如此对象便可直接在栈帧上进行分配,有效减小JVM垃圾回收的压力。

 Map<Integer, User> userMap = new HashMap<>();


    public int getUserAgeById(int id) {
       User user = new User();
        user.setId(RandomUtil.randomInt(10));
        user.setName(RandomUtil.randomString(3));
        //打印用户信息
        printUserInfo(user);
    }

2.分离对象或标量替换

如果仅仅是操作未逃逸对象的某些简单运算,我们同样可以只在栈帧内使用这个对象,如此JVM就会将这个对象打散,将对象打散为无数个小的局部变量,实现标量替换,如下所示,这段代码没有发生逃逸,则JVM会避免创建Point 。

public static void main(String args[]) {
    alloc();
}
class Point {
    private int x;
    private int y;
}
private static void alloc() {
    Point point = new Point(1,2);
    System.out.println("point.x" + point.x + ";point.y" + point.y);
}

进而直接标量替换,直接在栈上分配x和y的值,完成输出打印。

private static void alloc() {
    int x = 1;
    int y = 2;
    System.out.println("point.x = " + x + "; point.y=" + y);
}

3.同步锁消除

这一点就比较有趣了,我们都知道使用StringBuffer可以保证线程安全,因为其操作函数都有带synchronized关键字,那么请问这段代码会上锁吗?

public void appendStr(int count) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < count; i++) {
            sb.append("no: " + i + " ");
        }
    }

答案是不会,因为我们当前操作的StringBuffer 对象并没有发生逃逸,它仅仅是根据外部传入的count完成拼接并打印结果而已,于是JIT就会进行锁消除的优化操作。如下字节码所示,优化后的StringBuffer被替换为StringBuilder。

三、逃逸分析更进一步

了解了逃逸分析止之后,我们不妨基于下面这些题目进行一下自测,如下代码,请问实例方法调用静态方法,StringBuffer作为变量传入,是否发生逃逸,最终执行代码是StringBuffer 还是StringBuilder?

public void appendStr(int count) {
        StringBuffer sb = new StringBuffer();
        loop(count, sb);
    }

    private static void loop(int count, StringBuffer sb) {
        for (int i = 0; i < count; i++) {
            sb.append("no: " + i + " ");
        }
    }

答案是未发生逃逸,因为对象并没有被外部线程操作,JIT感知到未发生逃逸,所以将StringBuffer 转为StringBuilder。

再来看看这段代码,请问发生逃逸了吗?

 public void appendStr(int count) {
        StringBuffer sb = new StringBuffer();
        loop(count, sb);
    }

    private static String loop(int count, StringBuffer sb) {
        for (int i = 0; i < count; i++) {
            sb.append("no: " + i + " ");
        }
        return sb.toString();
    }

答案还是没有,返回的字符串还是没有被外部线程操作,所以最终还是被转为StringBuilder:

四、小结

合理的在栈帧上解决问题可以避免对象逃逸,从而让JIT尽可能的去进行优化,这一点我想应该是一个Java程序员对于代码的极致追求了。

责任编辑:赵宁宁 来源: 写代码的SharkChili
相关推荐

2013-12-17 17:05:20

iOS性能优化

2023-12-22 07:55:38

Go语言分配策略

2024-05-16 11:04:06

C#异步编程编程

2019-11-11 14:51:19

Java数据结构Properties

2019-11-14 09:53:30

Set集合存储

2010-08-10 13:58:00

Flex性能测试

2013-11-14 15:53:53

AndroidAudioAudioFlinge

2019-02-01 09:50:00

提升Python程序性能

2021-03-16 08:54:35

AQSAbstractQueJava

2011-07-04 10:39:57

Web

2015-08-06 14:02:31

数据分析

2018-03-15 09:13:43

MySQL存储引擎

2011-09-20 10:41:45

Web

2022-10-08 13:13:14

Python程序性能

2018-07-06 16:26:11

编程语言Python程序性能

2022-12-02 09:13:28

SeataAT模式

2009-11-30 16:46:29

学习Linux

2012-05-21 10:06:26

FrameworkCocoa

2019-01-07 15:29:07

HadoopYarn架构调度器

2021-07-20 15:20:02

FlatBuffers阿里云Java
点赞
收藏

51CTO技术栈公众号