java逃逸分析

概念

  • 对象逃逸分析:是一种有效减少Java程序中同步负载和内存堆分配压力的跨函数全局数据流分析算法。通过逃逸分析,Java虚拟机能够分析出一个新的对象的引用范围从而决定是否要将这个对象分配到堆上。Java1.7后默认开启逃逸分析的选项。Java的JIT编译器,能够在方法重载或者动态加载代码的时候对代码进行逃逸分析,同时Java对象在堆上分配和内置线程的特点使得逃逸分析成Java的重要功能。
  • JIT技术 :为了解决JVM执行字节码速度问题。引入JIT(即时编译)技术,当JVM发现某个方法或代码块运行的特别频繁的时候,就会认为这是"热点代码" ,然后JIT会把部分热点代码翻译成本地机器相关的机器码,然后再把翻译后的机器码缓存起来,以备下次使用。

对象逃逸状态

基于逃逸分析,一个对象可以被三种逃逸状态标记。

  1. 全局级别逃逸状态

一个对象能从一个方法或者当前线程中逃逸,那么会被标记为全局逃逸状态

  1. 参数级别逃逸

如果一个对象被作为参数传递给一个方法,但是在这个方法之外无法访问或者对其他线程不可见,这个对象标记为参数级别逃逸。

  1. 不逃逸

一个对象不会产生逃逸。

逃逸分析的作用

通过逃逸分析,在不存在逃逸下JVM可以进行以下优化。

  • 同步消除

线程同步本身比较耗时,如果确定一个变量不会逃逸出线程,无法被其他线程访问到,那么这个变量的读写就不会存在竞争,对这个变量的同步措施可以清除。

  • 将堆分配转为栈上分配

在一般应用中,不会逃逸的局部对象占比很大,如果使用栈上分配,那大量对象会随着方法结束而自动销毁,减轻垃圾回收系统压力。

  • 分离对象或标量替换

标量就是不可分割的量,java中基本数据类型,reference类型都是标量。相对的一个数据可以继续分解,它就是聚合量。如果把一个对象拆散,将其成员变量恢复到基本类型来访问就叫做标量替换。如果逃逸分析证明一个对象不会被外部访问,并且这个对象可以被拆散的话,那么程序真正执行的时候可能在栈上创建若干个成员变量。

验证逃逸分析对对象分配的影响

验证代码如下:

java 复制代码
public static void main(String[] args) {
    long a1 = System.currentTimeMillis();
    for (int i = 0; i < 1000000; i++) {
        alloc();
    }
    // 查看执行时间
    long a2 = System.currentTimeMillis();
    System.out.println("cost " + (a2 - a1) + " ms");
    // 为了方便查看堆内存中对象个数,线程sleep
    try {
        Thread.sleep(100000);
    } catch (InterruptedException e1) {
        e1.printStackTrace();
    }
}

private static void alloc() {
    User user = new User();
}

static class User {

}

关闭逃逸分析

  • 配置JVM参数

-Xmx4G -Xms4G -XX:-DoEscapeAnalysis -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError

-通过jmap命令分析堆对象

powershell 复制代码
➜  ~ jps
2809 StackAllocTest
2810 Jps
➜  ~ jmap -histo 2809

 num     #instances         #bytes  class name
----------------------------------------------
   1:           524       87282184  [I
   2:       1000000       16000000  StackAllocTest$User
   3:          6806        2093136  [B
   4:          8006        1320872  [C
   5:          4188         100512  java.lang.String
   6:           581          66304  java.lang.Class

从上面的jmap执行结果中我们可以看到,堆中共创建了100万个StackAllocTest$User实例。

  • 结论
    关闭逃逸分析的情况下,对象分配在堆上。

开启逃逸分析

  • 配置JVM参数

Xmx4G -Xms4G -XX:+DoEscapeAnalysis -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError

  • 通过jmap命令分析堆对象
powershell 复制代码
➜  ~ jps
709
2858 Launcher
2859 StackAllocTest
2860 Jps
➜  ~ jmap -histo 2859

 num     #instances         #bytes  class name
----------------------------------------------
   1:           524      101944280  [I
   2:          6806        2093136  [B
   3:         83619        1337904  StackAllocTest$User
   4:          8006        1320872  [C
   5:          4188         100512  java.lang.String
   6:           581          66304  java.lang.Class

从以上打印结果中可以发现,开启了逃逸分析之后(-XX:+DoEscapeAnalysis),在堆内存中只有8万多个StackAllocTest$User对象。也就是说在经过JIT优化之后,堆内存中分配的对象数量,从100万降到了8万。

参考

java 逃逸问题 java 逃逸分析技术

相关推荐
凡人的AI工具箱13 分钟前
15分钟学 Go 第 60 天 :综合项目展示 - 构建微服务电商平台(完整示例25000字)
开发语言·后端·微服务·架构·golang
陈王卜15 分钟前
django+boostrap实现发布博客权限控制
java·前端·django
小码的头发丝、16 分钟前
Spring Boot 注解
java·spring boot
java亮小白199721 分钟前
Spring循环依赖如何解决的?
java·后端·spring
飞滕人生TYF27 分钟前
java Queue 详解
java·队列
chnming198728 分钟前
STL关联式容器之map
开发语言·c++
进击的六角龙30 分钟前
深入浅出:使用Python调用API实现智能天气预报
开发语言·python
檀越剑指大厂30 分钟前
【Python系列】浅析 Python 中的字典更新与应用场景
开发语言·python
湫ccc38 分钟前
Python简介以及解释器安装(保姆级教学)
开发语言·python
程序伍六七42 分钟前
day16
开发语言·c++