什么是逃逸分析

文章目录

    • [1. 对象的三个"逃逸"等级](#1. 对象的三个“逃逸”等级)
    • [2. 逃逸分析后能做什么?(三大神技)](#2. 逃逸分析后能做什么?(三大神技))
      • [① 栈上分配 (Stack Allocation) ------ 最核心的优化](#① 栈上分配 (Stack Allocation) —— 最核心的优化)
      • [② 标量替换 (Scalar Replacement)](#② 标量替换 (Scalar Replacement))
      • [③ 同步消除 (Lock Elision)](#③ 同步消除 (Lock Elision))
    • [3. 它是如何判断对象"逃逸"的?](#3. 它是如何判断对象“逃逸”的?)
    • [4. 为什么要强调它是 JIT 的功能?](#4. 为什么要强调它是 JIT 的功能?)
    • 总结

逃逸分析的核心目的就是判断有没有多线程竞争,如果没有多线程竞争,就会删除锁,提高性能

它的核心任务是:分析一个在方法内创建的对象,它的生命周期是否会超出这个方法的范围(即"逃出"当前方法的控制)。


1. 对象的三个"逃逸"等级

JVM 会根据对象的使用范围,将其标记为三个等级:

  1. 从不逃逸 (No Escape):对象只在当前方法内使用,方法结束,对象就没用了。
  2. 方法逃逸 (Arg Escape):对象作为参数传递给了其他方法,或者被赋值给了其他线程能看到的变量。
  3. 线程逃逸 (Global Escape):对象被赋值给了类变量(static)或者存入了堆中,其他线程可以访问它。

2. 逃逸分析后能做什么?(三大神技)

一旦分析出对象"没有逃逸",JVM 就可以大胆地进行以下"骚操作"来提升性能:

① 栈上分配 (Stack Allocation) ------ 最核心的优化

  • 传统逻辑:Java 几乎所有的对象都在**堆(Heap)**上分配。堆是共享的,创建对象需要加锁找空间,回收对象需要 GC(垃圾回收),压力很大。
  • 优化逻辑:如果对象不逃逸,JVM 就直接在**栈(Stack)**上分配。
  • 结果 :方法一执行完,栈帧弹出,对象直接随之销毁。完全不需要 GC 介入,效率极高。

② 标量替换 (Scalar Replacement)

  • 概念 :有些对象可能不需要作为一个完整的"块"存在。比如一个 Point 对象只有 int x 和 int y。
  • 优化逻辑 :如果不逃逸,JVM 会把这个对象拆解掉,直接在栈上创建两个基本类型的变量 x 和 y。
  • 结果:连对象头(Object Header)的内存开销都省了,直接变成了寄存器或栈上的基本运算。

③ 同步消除 (Lock Elision)

  • 这就是你之前提到的:如果对象不逃逸,说明只有当前线程能看到它,那它身上的 synchronized 锁就是摆设,JIT 会直接把锁删掉。

3. 它是如何判断对象"逃逸"的?

让我们看一段直观的代码:

java 复制代码
public class EscapeTest {
    public static Object globalVariable;

    // 场景 1:发生逃逸(Global Escape)
    public void globalEscape() {
        Object obj = new Object();
        globalVariable = obj; // 对象被全局变量引用,逃逸了
    }

    // 场景 2:发生逃逸(Arg Escape)
    public Object methodEscape() {
        Object obj = new Object();
        return obj; // 对象被返回给了调用者,逃逸了
    }

    // 场景 3:没有逃逸(No Escape)
    public void noEscape() {
        Object obj = new Object(); // 仅在方法内使用
        System.out.println(obj.hashCode());
    }
}

4. 为什么要强调它是 JIT 的功能?

逃逸分析是一项耗时的静态分析。

  • 如果 JVM 在启动时对每一行逻辑都做分析,Java 启动会慢得像蜗牛。
  • 因此,逃逸分析通常只发生在热点代码(经常被调用的代码)上,由 C2 编译器在运行时动态进行。

总结

逃逸分析就像是一个"侦探",它观察对象的动向:

  • 如果发现对象是"宅男"(不出方法区),就给它安排栈上分配 和标量替换,省去 GC 麻烦。
  • 如果发现对象是"社交达人"(会逃到别处),那就老老实实去堆里待着。

这是 Java 能够在中大规模高并发场景下,依然保持极致性能的重要原因之一。

你现在对 Java 内存模型中的"堆"和"栈"的区分是否已经比较清晰了?这直接关系到为什么"栈上分配"会比"堆"快那么多。

相关推荐
y1su11 分钟前
Leetcode 动态规划 模板
java·数据结构·算法·leetcode·动态规划
Wang's Blog26 分钟前
Java 项目实战: 交友项目 - JWT 概述:为什么要用 Token 换掉 Session
java·ui·交友
SL_staff1 小时前
低代码选型避坑指南:为什么‘能拖拽’不等于‘能交付’?——基于JVS八大引擎的四维交付能力评估框架
java·低代码·spring cloud
李福春1 小时前
技术思考问题6:技术演讲该晒成功架构,还是交代失败与取舍?
java·开发语言·架构·computer use·深圳同盟·腾讯云架构师技术同盟·反演思维
用户7771298509122 小时前
equals和==的区别
java
旋律4142 小时前
对封装、继承、多态三个概念理解
java
code2cat2 小时前
【随笔】LLM裁判如何打分:先写评分标准,再用人工案例校准
java·人工智能·llm·agent·评估·langsmith
SL_staff2 小时前
计息规则不再等IT:JVS-Rules函数计算器在金融计息场景的技术实践
java·git·全栈