new出来的对象,不一定在堆上?聊聊Java虚拟机的优化技术:逃逸分析

简介: 逃逸分析是一种静态程序分析技术,用于判断对象的可见性与生命周期。它帮助即时编译器优化内存使用、降低同步开销。根据对象是否逃逸出方法或线程,分析结果分为未逃逸、方法逃逸和线程逃逸三种。基于分析结果,编译器可进行同步锁消除、标量替换和栈上分配等优化,从而提升程序性能。尽管逃逸分析计算复杂度较高,但其在热点代码中的应用为Java虚拟机带来了显著的优化效果。

逃逸分析(Escape Analysis)是一种静态程序分析技术,主要用于判定对象的可见范围(Visibility)与生命周期(Lifetime)。该技术是现代即时编译器实现局部化优化、提升内存使用效率、降低同步成本的基础。
通俗来说,逃逸分析的核心在于回答这样一个问题:某个对象是否可能“逃逸”出它所创建的方法或线程作用域?
逃逸分析的结果通常分为三种情形。
1)未逃逸(No Escape):对象完全局限在当前方法内,既未作为返回值,也未传递到其他线程或方法。
2)方法逃逸(Method Escape):对象作为参数传递到其他方法中,虽然不一定跨线程访问,但由于编译器无法确定外部方法的副作用,因此仍视为潜在逃逸。
3)线程逃逸(Thread Escape):对象的引用被赋值给共享变量,或作为任务传递给其他线程。这类对象无法进行逃逸相关优化,必须保留其线程安全保障。
下面代码的是对象未逃逸的例子:

// add方法中创建了一个名为NonEscapeObject的对象。
// 这个对象仅在add方法中使用,用于计算两个整数的和。
// 这个对象没有作为方法的返回值、赋值给全局变量或作为参数传递给其他方法。
// 因此它被认为是未逃逸的。
int add(int a, int b) {
   

  NonEscapeObject o = new NonEscapeObject(a, b);

  return obj.getX() + obj.getY();
}

class NonEscapeObject {
   

    private int x;

    private int y;
}

基于逃逸分析的信息,即时编译器可以执行一些优化,例如同步锁消除(Synchronization Elimination)、标量替换(Scalar Replacement)和栈上分配(Stack allcotion)。

同步锁消除
线程同步是一个相对耗时的过程,如果逃逸分析能确定一个共享变量不会逃出线程,无法被其他线程访问,那这个共享变量的读写肯定就不会有竞争,对这个变量实施的同步措施也就可以消除掉。

// 由于obj没有逃逸出doSomething()方法的范围,编译器可以进行逃逸分析并确定该对象不会被其他线程访问。
// 在逃逸分析确定obj对象不会逃逸的情况下,编译器可以消除对该对象的同步锁操作。
void doSomething() {
   

    Object obj = new Object();

    synchronized (obj) {
   

        // 对obj进行一些操作

        // ...
    }
}

标量替换
标量(scalar)是指一个无法再分解成更小的数据的数据。Java 中的基本数据类型就是标量。相对的Java 中的对象就是聚合量(Aggregate),因为它可以分解成其他聚合量和标量。
如果经过逃逸分析,发现一个对象并没有逃逸出方法和线程,那么就可以将这个对象视为一组标量值。这样,Java虚拟机就可以将这个对象的所有字段视为局部变量,从而在栈上分配这些局部变量,而不是在堆上分配整个对象,这样可以减少堆内存的占用。

void test() {
   

   Point point = new Point(1,2);

   System.out.println("point.x" + point.x + ";point.y" + point.y);
}

class Point {
   

    private int x;

    private int y;
}

假设有一个Point对象,包含x和y两个字段。如果经过逃逸分析,发现这个Point对象并没有逃逸出方法,那么Java虚拟机就可以将这个Point对象视为两个独立的标量值x和y,然后在栈上分配这两个值,而不是在堆上分配整个Point对象。

void test() {
   
    int x = 1;

    int y = 2;

    System.out.println("point.x = " + x + "; point.y=" + y);
}

栈上分配
Java的对象是在堆上分配的,Java虚拟机对堆内存的垃圾对象回收是一个耗时的过程。在一般应用中,不会逃逸的局部对象所占的比例很大,如果能使用栈上分配,那大量的对象就会随着方法的结束而自动销毁,垃圾收集系统的压力将会小很多。
虽然逃逸分析理论上支持将非逃逸对象直接分配到栈上,从而避免堆内存开销与垃圾回收成本,但如HotSpot虚拟机并未真正实现物理意义上的栈上分配。原因在于:在支持线程抢占、嵌套调用、异常恢复与栈帧迁移(如逃逸到堆)等复杂运行时语义的情况下,栈上对象生命周期管理的正确性将变得异常困难,容易引发并发可见性等问题。因此,Hotspot虚拟机并没有进行实际的栈上分配,而是使用了标量替换这一技术。
尽管逃逸分析为即时编译器带来了多种激进优化的可能,但它本身也是一项计算复杂度较高的静态分析技术。在分析过程中,编译器需要对对象的引用路径进行全程追踪,判断其是否会被其他线程访问、是否会通过方法返回或赋值跨出当前作用域。特别是在存在复杂控制流、间接调用或反射的情况下,分析准确性与代价都将急剧上升。
这种计算成本并非微不足道:在代码编译时长与运行时性能收益之间,并不总是呈现出正向关系。在某些边缘场景中,逃逸分析所带来的优化甚至可能因分析开销过大、代码形态不佳(例如过度拆箱、短生命周期对象)而无法收回性能投入。因此,Java虚拟机会采用热点代码触发机制,仅对高频路径进行逃逸分析,以期在收益与成本之间实现动态平衡。
虽然这项技术并不十分成熟,但是它也是即时编译器优化技术中一个十分重要的手段。

未完待续

很高兴与你相遇!如果你喜欢本文内容,记得关注哦!

目录
相关文章
|
25天前
|
缓存 Rust Java
没有Happens-Before?你的多线程代码就是‘一锅粥’!
并发编程中,Java内存模型(JMM)通过happens-before规则定义线程间操作的顺序与可见性,确保多线程环境下程序的正确性。它抽象底层硬件差异,提供volatile、synchronized等同步机制,简化并发开发,实现高效、可移植的多线程程序。
143 0
|
4天前
|
存储 测试技术 开发者
NVFP4量化技术深度解析:4位精度下实现2.3倍推理加速
本文深入解析NVIDIA推出的NVFP4量化技术,探讨其在Blackwell GPU架构下的性能优势。通过对比主流4位量化方法,分析NVFP4在精度、内存和推理吞吐量方面的表现,结合LLM-Compressor与vLLM框架展示量化与部署实践,验证其在消费级与企业级应用中的高效性与实用性。
64 15
NVFP4量化技术深度解析:4位精度下实现2.3倍推理加速
|
12天前
|
算法 搜索推荐 大数据
大数据搅动娱乐圈:流量造星还是内容为王?
大数据搅动娱乐圈:流量造星还是内容为王?
55 13
|
12天前
|
传感器 人工智能 监控
戴手环太土了?皮肤植入式传感器才是健康监测的终极形态
戴手环太土了?皮肤植入式传感器才是健康监测的终极形态
73 12
|
7天前
|
传感器 人工智能 安全
AI智能体架构详解:从LLM核心到工具扩展的自主进化之旅
AI正从响应指令的工具,迈向能自主理解、规划和执行复杂任务的智能体(AI Agent)时代。它像拥有“大脑与四肢”的完整个体,通过感知-规划-行动循环实现目标,核心架构包含推理引擎、记忆系统和工具集等组件。本文深入解析其工作原理、主流架构及面临的挑战与未来。
|
21天前
|
人工智能 自然语言处理 算法
提升LangChain开发效率:10个被忽视的高效组件,让AI应用性能翻倍
LangChain作为主流大语言模型应用框架,其高级组件常被忽视。本文详解10个高价值但低使用率的核心组件,如语义检索、多模板路由、智能查询转换等,结合技术原理与实践案例,助开发者构建更高效、智能、适应性强的AI系统,提升应用性能与业务价值。
130 0
|
23天前
|
JSON 监控 BI
深度分析亚马逊API接口,用Python脚本实现
本内容深度解析亚马逊SP-API接口体系,涵盖商品、订单、库存等核心功能域,详解LWA认证、AWS签名及Python调用实现,适用于跨境电商系统开发与集成。
|
23天前
|
JSON 缓存 API
深度分析淘宝API接口,用Python脚本实现
本内容深入解析淘宝开放平台 API 的接口设计与 Python 实现,涵盖接口体系、认证机制、签名规则及限流策略,并提供完整的 Python 调用框架,适用于电商系统对接与自动化运营。
|
24天前
|
人工智能 运维 Prometheus
运维再不“聪明点”,迟早被业务拖垮!
运维再不“聪明点”,迟早被业务拖垮!
99 0
|
6天前
|
存储 Prometheus 监控
从入门到实战:一文掌握微服务监控系统 Prometheus + Grafana
随着微服务架构的发展,系统监控变得愈发重要。本文介绍如何利用 Prometheus 和 Grafana 构建高效的监控系统,涵盖数据采集、存储、可视化与告警机制,帮助开发者提升系统可观测性,及时发现故障并优化性能。内容涵盖 Prometheus 的核心组件、数据模型及部署方案,并结合 Grafana 实现可视化监控,适合初学者和进阶开发者参考实践。
150 6