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 逃逸分析技术

相关推荐
源代码•宸1 小时前
分布式缓存-GO(分布式算法之一致性哈希、缓存对外服务化)
开发语言·经验分享·分布式·后端·算法·缓存·golang
云和数据.ChenGuang1 小时前
PHP-FPM返回的File not found.”的本质
开发语言·php·运维工程师·运维技术
It's now1 小时前
Spring AI 基础开发流程
java·人工智能·后端·spring
cxh_陈1 小时前
线程的状态,以及和锁有什么关系
java·线程·线程的状态·线程和锁
计算机毕设VX:Fegn08952 小时前
计算机毕业设计|基于springboot + vue图书商城系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·课程设计
R.lin2 小时前
Java 8日期时间API完全指南
java·开发语言·python
毕设源码-赖学姐2 小时前
【开题答辩全过程】以 高校教学质量监控平台为例,包含答辩的问题和答案
java·eclipse
高山上有一只小老虎2 小时前
翻之矩阵中的行
java·算法
yangpipi-2 小时前
《C++并发编程实战》 第4章 并发操作的同步
开发语言·c++
火钳游侠2 小时前
java单行注释,多行注释,文档注释
java·开发语言