JVM逃逸分析机制

JVM逃逸分析机制

简单来说,逃逸分析是分析了对象是否只在当前函数范围内使用,来确定是否在栈上进行分配,主要涉及到栈是函数运行完,立即清理的,所以不需要等到gc了,为了大大缓解了gc的压力。

一、定义

JVM 逃逸分析(Escape Analysis)是一种可以有效优化 Java 程序性能的技术手段,它是 Java 虚拟机在编译阶段(即时编译器,Just In Time compiler,JIT)进行的一项重要的优化分析工作。逃逸分析主要用于判断对象的作用域是否会 “逃逸” 出当前方法、线程或者其他特定的代码范围,如果对象不会逃逸,那么虚拟机就可以基于此进行一些针对性的优化。

二、判断对象是否逃逸的依据和场景
(一)方法逃逸(Method Escape)

  • 含义:如果一个对象在方法内部被创建,但有可能在该方法执行结束后,其引用被外部方法、线程或者其他代码所获取并访问,那么这个对象就发生了方法逃逸。

  • 示例场景: 比如,在一个方法中创建了一个对象,然后将这个对象作为返回值返回给调用者,那么这个对象显然就逃逸出了它被创建的方法,外部代码可以通过获取返回值的方式来操作该对象。如下代码所示:

 public class EscapeExample {public static Object createObject() {Object obj = new Object();return obj;}}

在上述 createObject 方法中创建的 Object 实例 obj 就发生了方法逃逸,因为它被作为返回值传递到了方法外部。通过逃逸分析后,就不允许对象obj在栈上分配,因为这里的obj需要返回给调用者。

如果void返回类型,就允许在栈上分配,因为不需要返回给调用者,方法执行结束,栈是函数运行完,立即清理的,所以不需要等到gc了,大大缓解了gc的压力。

另外一种常见的情况是,将对象作为参数传递给其他方法,并且在其他方法中该对象的引用有可能被保存下来或者继续传播,例如:

 public class AnotherEscapeExample {public static void setObjectInList(List<Object> list) {Object obj = new Object();list.add(obj);}}

setObjectInList 方法中,创建的 Object 实例 obj 被添加到了传入的 List 中,而这个 List 是外部传入的,意味着 obj 的引用可以通过这个 List 在方法外部被访问到,所以 obj 也发生了方法逃逸。

(二)线程逃逸(Thread Escape)

  • 含义:如果一个对象在某个线程中被创建,但有可能被其他线程访问到,那么该对象就发生了线程逃逸。

  • 示例场景: 例如,在多线程环境下,一个对象被创建后存放在了一个可以被多个线程共享的静态变量中,如下代码:

 public class ThreadEscapeExample {static Object sharedObject;​public static void createAndShareObject() {sharedObject = new Object();}}

createAndShareObject 方法中创建的 Object 实例被赋值给了静态变量 sharedObject,由于静态变量是所有线程都可以访问到的,所以这个对象就发生了线程逃逸,其他线程可以获取并操作这个 sharedObject

三、基于逃逸分析的优化策略
(一)栈上分配(Stack Allocation)

  • 原理:通常情况下,Java 对象是在堆内存中分配空间的,但如果经过逃逸分析发现一个对象不会逃逸出方法(即没有方法逃逸),那么这个对象就可以直接在栈上分配内存。栈内存有一个特点,就是随着方法的执行结束,栈帧出栈,栈上分配的对象所占用的内存空间会自动被回收,无需像堆内存那样依赖垃圾收集器来回收,这样可以减少堆内存的使用压力,同时也提高了内存回收的效率,因为省去了垃圾收集的相关开销。

  • 示例: 考虑如下代码:

 public void localObjectAllocation() {for (int i = 0; i < 1000; i++) {Object localObj = new Object();// 对localObj进行一些简单操作,比如调用其toString方法等System.out.println(localObj.toString());}}

如果经过逃逸分析确定 localObj 在每次循环中都不会逃逸出 localObjectAllocation 这个方法,那么 JVM 就可以将这些 Object 实例直接在栈上进行分配,循环结束后,随着方法栈帧的销毁,这些对象占用的内存自动释放,无需进行堆内存的分配和垃圾收集等操作。

(二)标量替换(Scalar Replacement)

  • 原理:标量(Scalar)是指那些不能再分解的数据类型,比如基本数据类型(int、double、boolean 等)以及对象的引用等。在 Java 中,对象是由多个成员变量等组成的聚合体。如果经过逃逸分析发现一个对象不会逃逸,并且这个对象可以拆解为若干个标量来替代它进行使用,那么 JVM 就会采用标量替换的优化策略。即将对象的成员变量等按照使用的顺序和逻辑,用对应的标量在栈上或者寄存器中进行表示和操作,这样就相当于消除了对象的实例化过程,进一步节省了内存空间和提高了执行效率。

  • 示例: 假设有如下一个简单的类:

 class Point {private int x;private int y;}

在某个方法中有如下代码:

 public void usePoint() {Point point = new Point();point.x = 10;point.y = 20;int sum = point.x + point.y;}

如果经过逃逸分析确定 point 对象不会逃逸出 usePoint 方法,JVM 可能会进行标量替换,直接在栈上用两个 int 类型的变量(分别对应 pointxy 属性)来替代 Point 对象的实例,在后续的代码执行中按照原来操作 Point 对象的逻辑去操作这两个 int 变量,避免了创建 Point 对象实例以及相关的内存分配等开销。

(三)同步消除(Synchronization Elimination)

  • 原理:在多线程编程中,为了保证线程安全,我们经常会对代码块或者方法添加 synchronized 关键字来实现同步。但如果经过逃逸分析发现某个加锁的对象不会发生线程逃逸,也就是只有当前创建它的线程能够访问到它,那么这个对象实际上不存在多线程并发访问的情况,此时 JVM 就可以把对应的同步锁操作消除掉,避免了获取和释放锁带来的性能开销,提高代码的执行效率。

  • 示例: 如下代码中,原本对 localObj 进行了加锁操作:

 public void synchronizedLocalObject() {Object localObj = new Object();synchronized (localObj) {// 对localObj进行一些操作System.out.println(localObj.toString());}}

如果逃逸分析判断 localObj 不会逃逸出这个方法,也就是不会被其他线程访问到,那么 JVM 就可以消除这里的 synchronized 操作,按照正常的非同步代码逻辑来执行后续对 localObj 的操作,减少了加锁和解锁的性能损耗。

四、总结

JVM 逃逸机制通过对对象逃逸情况的分析,能够挖掘出可以进行性能优化的潜在机会,然后采用栈上分配、标量替换、同步消除等优化策略,在不改变 Java 代码语义的前提下,有效地提高 Java 程序的运行性能,尤其是在内存使用和执行效率方面,让 Java 应用在各种复杂的场景下能够更加高效地运行。不过需要注意的是,逃逸分析本身也是有一定的性能开销的,不同的 JVM 实现以及不同的编译参数设置等都会影响逃逸分析的效果以及相关优化策略的实施情况。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/61082.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Petri网导论学习笔记】Petri网导论入门学习(十) —— 3.2 关联矩阵与状态方程

目录 3.2 关联矩阵与状态方程定义 3.3 关联矩阵引理 3.4引理 3.5定理 3.4例 3.7例 3.83.2 关联矩阵与状态方程 正如 Petri 网的一个标识可以表示成一个 $ m $ 维非负整数向量一样,Petri 网的结构也可以用一个矩阵来表示。这样,就可以引入线性代数的方法对 Petri 网的性质进行…

微信小程序常用全局配置项及窗口组成部分详解

微信小程序常用全局配置项及窗口组成部分详解 引言 微信小程序作为一种新兴的应用形态,凭借其轻量级、便捷性和丰富的功能,已成为开发者和用户的热门选择。在开发小程序的过程中,了解全局配置项和窗口组成部分是至关重要的。本文将详细介绍微信小程序的常用全局配置项及窗…

【H2O2|全栈】Node.js(1)

目录 前言 开篇语 准备工作 ES6导入导出 导入 有名导出 匿名导出 Node概念 Node导入导出 导入 有名导出 匿名导出 Node常用模块 path模块 和路径有关的全局变量 常见方法 导入方法 fs模块 常见方法 导入方法 结束语 前言 开篇语 本系列博客主要分享Java…

matlab -炉温串级控制PID

1、内容简介 略 92-可以交流、咨询、答疑 2、内容说明 略 基于PID的反馈控制能够使得炉温控制达到较好的控制效果&#xff0c;但系统的调节时间还是较长&#xff0c;一般都大于20分钟。考虑能否用其他系统来改进控制系统使得调节时间变短的同时还能满足控制要求。一种最直接…

#渗透测试#红蓝攻防#HW#经验分享#溯源反制

免责声明 本教程仅为合法的教学目的而准备,严禁用于任何形式的违法犯罪活动及其他商业行为,在使用本教程前,您应确保该行为符合当地的法律法规,继续阅读即表示您需自行承担所有操作的后果,如有异议,请立即停止本文章阅 目录 一、溯源反制 1、溯源反制的重要性 2、溯源…

java——SpringBoot中常用注解及其底层原理

SpringBoot中的注解是简化配置、自动装配组件和实现声明式服务的关键。以下是对SpringBoot中常用注解及其底层原理的详细解析&#xff1a; 常用注解 SpringBootApplication 标注在主程序类上&#xff0c;表示这是一个Spring Boot应用的入口。它是一个复合注解&#xff0c;包括…

redis-cluster集群搭建

集群节点信息 192.168.222.131:46379 主要节点1 192.168.222.131:46380 从节点1 192.168.222.131:46381 从节点2192.168.222.132:46379 主要节点2 192.168.222.132:46380 从节点1 192.168.222.132:46381 从节点2192.168.222.133:46379 主要节点3 192.168.222.133:46380 从节点…

探索Python WebSocket新境界:picows库揭秘

文章目录 探索Python WebSocket新境界&#xff1a;picows库揭秘第一部分&#xff1a;背景介绍第二部分&#xff1a;picows库概述第三部分&#xff1a;安装picows库第四部分&#xff1a;简单库函数使用方法第五部分&#xff1a;场景应用第六部分&#xff1a;常见Bug及解决方案第…

QT-installEventFilter

installEventFilter 是 Qt 框架中的一个方法&#xff0c;用于在对象之间建立事件过滤机制。具体来说&#xff0c;它允许一个对象&#xff08;称为事件过滤器&#xff09;监视另一个对象&#xff08;称为被监视对象&#xff09;的事件&#xff0c;并在这些事件被处理之前对其进行…

dmdba用户资源限制ulimit -a 部分配置未生效

dmdba用户资源限制ulimit -a 部分配置未生效 1 环境介绍2 数据库实例日志报错2.1 mpp01 实例日志报错2.2 mpp02 实例日志报错 3 mpp02 服务器资源限制情况4 关闭SELinux 问题解决4.1 临时关闭 SELinux4.2 永久关闭 SELinux 5 达梦数据库学习使用列表 1 环境介绍 Cpu x86 Os Ce…

Linux基本指令的使用

当然可以&#xff01;以下是一些常用的Linux指令及其示例&#xff1a; 1. ls 列出目录内容。 ls 显示当前目录下的文件和文件夹。 ls -l 以详细格式列出文件和文件夹的信息&#xff08;如权限、拥有者、大小等&#xff09;。 2. cd 改变当前目录。 cd /path/to/dire…

安卓悬浮窗应用外无法穿透事件问题

现象&#xff1a; 应用内悬浮窗如何设置了 WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE在自己应用内事件穿透正常&#xff0c;但到应用外就无法点击。 原因&#xff1a; 解决方法&#xff1a; layoutParams.alpha 0.8f …

c++趣味编程玩转物联网:基于树莓派Pico控制有源蜂鸣器

有源蜂鸣器是一种简单高效的声音输出设备&#xff0c;广泛应用于电子报警器、玩具、计时器等领域。在本项目中&#xff0c;我们结合树莓派Pico开发板&#xff0c;通过C代码控制有源蜂鸣器发出“滴滴”声&#xff0c;并解析其中涉及的关键技术点和硬件知识。 一、项目概述 1. 项…

ubuntu+ROS推视频流至网络

目录 概述 工具 ros_rtsp 接受流 web_video_server 源码安装 二进制安装 ros接收rtsp视频流 总结 概述 ros_rtsp功能包可以将ros视频流以rtsp形式推送 web_video_server功能包可以将ros视频话题推HTTP流 rocon_rtsp_camera_relay可以接受同一网段下的rtsp视频流输出为…

探索光耦:光耦安全标准解读——确保设备隔离与安全的重要规范

在现代科技日新月异的今天&#xff0c;光耦&#xff08;光电耦合器&#xff09;作为电子设备中不可或缺的隔离元件&#xff0c;其重要性不言而喻。它不仅在电源调控、工业自动化及医疗设备等关键领域大显身手&#xff0c;更是确保系统电气隔离与运行稳定的守护神。特别是在保障…

什么是 C++ 中的函数对象?它有什么特点?

在 C 中&#xff0c;函数对象&#xff08;Function Object&#xff09;是一种可调用对象&#xff0c;它允许像函数一样被调用&#xff0c;但实际上它可能并不是真正的函数。函数对象可以是以下几种类型之一&#xff1a; 普通函数&#xff1a; 一个普通的、定义在命名空间或类…

uni-app自定义底部tab并且根据字段显示和隐藏

首先将所有tab使用到的页面创建好并且在pages里面配置好&#xff0c;要在pages.json中的"tabBar里面配置"custom": true将自带的tab底部导航关闭 "pages": [{"path": "pages/mine/mine","style": {"navigationBa…

C/C++基础知识复习(31)

1) 什么是 C 中的多继承&#xff1f;它有哪些优缺点&#xff1f; 多继承&#xff08;Multiple Inheritance&#xff09;是指在 C 中&#xff0c;一个类可以继承自多个基类&#xff0c;从而拥有多个基类的特性和行为。具体来说&#xff0c;子类可以通过继承多个父类&#xff0c…

Qt程序发布及打包成exe安装包

参考:Qt之程序发布以及打包成exe安装包 目录 一、简述 Qt 项目开发完成之后,需要打包发布程序,而因为用户电脑上没有 Qt 配置环境,所以需要将 release 生成的 exe 文件和所依赖的 dll 文件复制到一个文件夹中,然后再用 Inno Setup 打包工具打包成一个 exe 安装包,就可以…

JAVA题目笔记(二十)异常综合小练

一、键盘录入数据 import java.text.ParseException; import java.util.InputMismatchException; import java.util.Scanner;public class Co {public static void main(String[] args) throws ParseException {//键盘录入信息int age0;String namenull;Scanner sc new Scanne…