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,一经查实,立即删除!

相关文章

matlab -炉温串级控制PID

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

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

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

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

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

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…

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

现象&#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;更是确保系统电气隔离与运行稳定的守护神。特别是在保障…

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…

STM32F10x 定时器

使用定时器实现&#xff1a;B5 E5的开关 添加相关的.h路径文件 添加相关的.c配置文件 led.h文件 用于声明LED函数 #ifndef __LED_H //没有定义__LED_H #define __LED_H //就定义__LED_H #define LED1_ON GPIO_ResetBits(GPIOB,GPIO_Pin_5) #defi…

shell脚本基础学习_总结篇(完结)

细致观看可以&#xff0c;访问shell脚本学习专栏&#xff0c;对应章节会有配图https://blog.csdn.net/2201_75446043/category_12833287.html?spm1001.2014.3001.5482 导语 一、shell脚本简介 1. 定义&#xff1a; 2. 主要特点&#xff1a; 3. shell脚本的基本结构 4. S…

Linux创建免密登陆(错误:Permission denied (publickey,gssapi-keyex,gssapi-with-mic))

报错截图 解决方法 1. mkdir -p ~/.ssh 2. chmod 700 ~/.ssh 3. ssh-keygen&#xff0c;一直回车 4. chmod 600 /root/.ssh/id_rsa 5. 将公钥内容追加到服务器上&#xff0c;cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys 6. chmod 600 ~/.ssh/authorized_keys…

低代码平台在医疗/医院行业应用案例与优势介绍

随着医疗行业的不断发展&#xff0c;数字化管理的需求日益迫切。传统的医疗信息化管理系统开发往往面临着成本高、周期长、定制性差等问题。在这个数字化转型的浪潮下&#xff0c;低代码平台应运而生&#xff0c;为医院快速搭建高效、灵活的医疗信息化管理系统提供了全新的解决…

在 Spring Boot 中构造 API 响应的最佳实践

在平时的开发和项目中&#xff0c;我们一定会涉及到接口对接的功能&#xff0c;由于不同开发人员的编码习惯不同&#xff0c;API报文在项目中通常是"百花齐放"的。 不但增加工作难度&#xff0c;往往也是扯皮的大头&#xff0c;如果能统一报文格式&#xff0c;不但能…

多目标优化算法——多目标粒子群优化算法(MOPSO)

Handling Multiple Objectives With Particle Swarm Optimization&#xff08;多目标粒子群优化算法&#xff09; 一、摘要&#xff1a; 本文提出了一种将帕累托优势引入粒子群优化算法的方法&#xff0c;使该算法能够处理具有多个目标函数的问题。与目前其他将粒子群算法扩展…

OpenCV与AI深度学习|16个含源码和数据集的计算机视觉实战项目(建议收藏!)

本文来源公众号“OpenCV与AI深度学习”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;分享&#xff5c;16个含源码和数据集的计算机视觉实战项目 本文将分享16个含源码和数据集的计算机视觉实战项目。具体包括&#xff1a; 1. 人…

Jenkins升级到最新版本后无法启动

1. 场景还原 最近在web界面将jenkins升级到最新版本后&#xff0c;后台无法启动jenkins服务&#xff0c;服务状态如下&#xff1a; 运行jenkins命令提示invalid Java version jenkins --version jenkins: invalid Java version: java version "1.8.0_202" Java(TM)…

【计算机视觉+MATLAB】自动检测并可视化圆形目标:通过 imfindcircles 和 viscircles 函数

引言 自动检测图像中的圆形或圆形对象&#xff0c;并可视化检测到的圆形。 函数详解 imfindcircles imfindcircles是MATLAB中的一个函数&#xff0c;用于在图像中检测并找出圆形区域。 基本语法&#xff1a; [centers, radii] imfindcircles(A, radiusRange) [centers, r…

鸿蒙NEXT元服务:利用App Linking实现无缝跳转与二维码拉起

【效果】 元服务链接格式&#xff08;API>12适用&#xff09;&#xff1a;https://hoas.drcn.agconnect.link/ggMRM 生成二维码后效果&#xff1a; 【参考网址】 使用App Linking实现元服务跳转&#xff1a;文档中心 草料二维码&#xff1a;草料二维码生成器 【引言】 …