JVM 锁优化和逃逸分析详解

news2025/7/29 4:13:09

1 锁优化

JVM 在加锁的过程中,会采用自旋、自适应、锁消除、锁粗化等优化手段来提升代码执行效率。

1.1 自旋锁和自适应自旋

现在大多的处理器都是多核处理器 ,如果在多核心处理器,有让两个或者以上的线程并行执行,我们可以让一个等待线程不放弃处理器的执行时间。设置一个等待超时时间,看线程是否能够很快的释放锁,在等等待的这段时间可以执行一个空循环,让当前线程继续占用 CPU 的时间片。这就是所谓的「自旋锁」。

JVM 中可以通过 +XX:UseSpinning来开启自旋锁,在 JDK1.6 过后默认为我们开启。由于自旋锁的使用会让锁的竞争者占用更多的处理器时间, JVM 规定了一个自旋次数的一个参数。我们可以通过 -XX:PreBlockSping来进行更改(默认10次)。

偏向锁、轻量级锁的状态转化及对象 Mark Word 的关系转换入下图所示:

1.2 锁消除

锁消除是指虚拟机即时编译器在运行时检测到某段需要同步的代码不可能存在共享数据竞争而实施的一种对锁进行消除的优化策略。锁消除的主要判断依据于逃逸分析。如果判断一段代码,在堆上所有的数据都不会逃逸出去被别的线程访问到,那就把它当作栈上的数据对待,认为它们是私有的,同步加锁就无需进行。

下面是三个字符串 x, y, z 相加的例子,无论是从源代码上还是逻辑上都没有进行同步:

public String concatStr(String x, String y, String z) {
    return  x + y + z;
}

String 是一个不可变的类,对字符的链接总是生成新的 String 对象来进行的,因此 Javac 编译器会对 String 链接进行自动优化,在 JDK5 之前字符串链接会转换为 StringBuffer;在 JDK5 之后会转换为 StringBuilder 对象连续的 append()操作,我们看看 javac 过后,反编译的结果:

public String concatStr(String x, String y, String z) {
    StringBuilder sb = new StringBuilder();
    sb.append(x);
    sb.append(y);
    sb.append(z);
    return  sb.toString();
}

我们再来看看 javap 反编译的结果:

这里大家可能会担心 StringBuilder 不是线程安全的的操作会存在线程安全的问题吗?这里的答案是不会,x + y + z 操作的优化「经过逃逸分析」过后,他的动态作用域被限制在了 concatStr方法内,就是说当前实际执行的 StringBuilder 的操作在 concatStr 方法内部,「其他的外部线程无法访问」到,所以这里「虽然有锁,但是可以被安全的消除掉。所以当我们进行编译过后,这段代码就会忽略掉所有的同步措施直接执行。」

1.3 锁粗化

原则上,我们在写代码的时候,总是推荐将同步块的作用范围限制得尽可能的小--只在共享数据的实际操作作用域中才进行同步,这样也是为了使得需要同步的操作尽可能的变少,即使存在锁的竞争,等待的锁的线程也能很快的获取到锁。大多数情况下,上面的原则都是正确的,但是如果「一系列的连续操作都是对同一个对象反复加锁和解锁,甚至加锁操作时出现在循环体之中」的,那即使没有线程的竞争,频繁的进行相互操作也会导致不必需要的性能损耗。

StringBuffer buffer = new StringBuffer();
/**  锁粗化 */ 
public void append(){
    buffer.append("aaa").append(" bbb").append(" ccc"); 
}

上面的代码每次调用 buffer.append 方法都需要加锁和解锁,如果 JVM 家册到有一串连续的对同一个对象加锁和解锁的操作,就会将其合并成一次范围更大的加锁解锁操作,即在第一个 append 方法执行的时候进行加锁,最后一个 append 方法结束后进行解锁。

2 逃逸分析

逃逸分析(Escape Analysis),是一种可能减少有效 Java 程序中同步负载和内存堆分配压力的跨全局函数数据流分析算法。通过逃逸分析, Java Hotspot 编译器能够分析出一个新的对象引用范围从而决定是否要将这个对象分配到堆上,「逃逸分析的基本行为就是分析对象的动态作用域。」

2.1 方法逃逸

当一个对象在方法里面被定义后,它可能被外部方法所引用,例如调用参数传递到其他方法中,这种称为方法逃逸。

例如:

    public static StringBuffer craeteStringBuffer(String s1, String s2) {

            StringBuffer sb = new StringBuffer();

            sb.append(s1);

            sb.append(s2);

            return sb;

        }

StringBuffer sb是一个方法内部变量,上述代码中直接将sb返回,这样这个StringBuffer有可能被其他方法所改变,这样它的作用域就不只是在方法内部,虽然它是一个局部变量,称其逃逸到了方法外部。

甚至还有可能被外部线程访问到,譬如赋值给类变量或可以在其他线程中访问的实例变量,称为线程逃逸。

上述代码如果想要StringBuffer sb不逃出方法,可以这样写:

    public static String createStringBuffer(String s1, String s2) {

            StringBuffer sb = new StringBuffer();

            sb.append(s1);

            sb.append(s2);

            return sb.toString();

        }

不直接返回 StringBuffer,那么StringBuffer将不会逃逸出方法。

如果能证明一个对象不会逃逸到方法或线程外,则可能为这个变量进行一些高效的优化。

2.2 线程逃逸

当一个对象可能被外部线程访问到,比如:赋值给其他线程中访问的实例变量,这种称为线程逃逸。

2.3 通过逃逸分析,编译器对代码的优化

如果能够证明一个对象不会逃逸到到方法外或线程外(其他线程方法或者线程无法通过任何方法访问该变量),或者逃逸程度比较低(只逃逸出方法而不逃逸出线程)则可以对这个对象采用不同程度的优化:

  1. 栈上分配(Stack Allocations)完全不会逃逸的局部变量和不会逃逸出线程的对象,采用栈上分配,对象就会跟随方法的结束自动销毁。以减少垃圾回收器的压力。

  1. 标量替换(Scalar Replacement)有个对象可能不需要作为一个连续的存储结果存储也能被访问到,那么对象的部分(或者全部)可以不存储在内存,而是存储在 CPU 寄存器中。

  1. 同步消除(Synchronization Elimination)如果一个对象发现只能在一个线程访问到,那么这个对象的操作可以考虑不同步。

总结:

虽然概念上的JVM总是在Java堆上为对象分配空间,但并不是说完全依照概念的描述去实现;只要最后实现处理的“可见效果”与概念中描述的一直就没问题了。所以说,“you can cheat as long as you don’t get caught”。Java对象在实际的JVM实现中可能在GC堆上分配空间,也可能在栈上分配空间,也可能完全就消失了。这种行为从Java源码中看不出来,也无法显式指定,只是聪明的JVM自动做的优化而已。

但是逃逸分析会有时间消耗,所以性能未必提升多少,并且由于逃逸分析比较耗时,目前的实现都是采用不那么准确但是时间压力相对较小的算法来完成逃逸分析,这就可能导致效果不稳定,要慎用。

由于HotSpot虚拟机目前的实现方法导致栈上分配实现起来比较复杂,因为在HotSpot中暂时还没有做这项优化。

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

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

相关文章

(免费分享)基于ssm的BBS社区论坛系统带论文

项目描述前台部分:1.用户注册登录模块用户登录后,可以进行发帖回帖功能,在线签到功能,完善个人信息,添加好友,收藏贴子,评论帖子,点赞功能,记录功能(比如记录今天发生的事情)等等…2.排行榜模块1.帖子讨论热度排行,分两种排行方式:(1) 根据用户今日发出的帖子被回复数量进行排名…

Linux USB 开发指南

文章目录Linux USB 开发指南1 前言1.1 文档简介1.2 目标读者1.3 适用范围2 模块介绍2.1 模块功能介绍2.2 相关术语介绍2.3 模块配置介绍2.3.1 Device Tree 配置说明2.3.2 board.dts 配置说明2.3.3 kernel menuconfig 配置说明2.4 源码结构介绍2.5 驱动框架介绍2.6 Gadget 配置2…

MySQL体系结构及数据库引擎

文章目录一、MYSQL的体系结构1、连接器2、查询缓存3、分析器(要做什么)4、优化器(怎么做)5、执行器6、数据库引擎1)mysql支持的引擎2)常用的mysql引擎比较3)索引组织表、堆组织表4)内…

大数据开发-Hive

1、hive简介 hive是基于Hadoop的一个数据仓库工具,用于分析数据的。可以将结构化数据文件映射为一张数据库表,并提供类SQL查询功能 注:hive-SQL or HQL or类SQL 和标准SQL还是有一点点区别的 本质是SQL转换为MapReduce程序 用途&#xff1…

Vulnhub靶场----6、DC-6

文章目录一、环境搭建二、渗透流程三、思路总结一、环境搭建 DC-6下载地址:https://download.vulnhub.com/dc/DC-6.zip kali:192.168.144.148 DC-6:192.168.144.154 靶机描述:选择带k01的密码后面会用到 访问192.168.144.154&…

秒杀测试案例 Java Redis Mysql

基于redis和MySQL乐观锁实现秒杀优惠券场景,一人一单。MySQL乐观锁改良控制不出现超卖和少卖问题,使用redisson分布式锁在用户维度加锁控制一人一单。 源码:https://github.com/hanhanhanxu/SeckillTest 文中图片看不清的地方可以鼠标右键-&…

01--微信小程序介绍

1、什么是微信小程序微信小程序,小程序的一种,英文名Wechat Mini Program,是一种不需要下载安装即可使用的应用,它实现了应用“触手可及”的梦想,用户扫一扫或搜一下即可打开应用。微信小程序是一种不需要下载安装即可…

python--排序总结

1.快速排序 a.原理 快速排序的基本思想是在待排序的 n 个元素中任取一个元素(通常取第一个元素)作为基准,把该元素放人最终位置后,整个数据序列被基准分割成两个子序列,所有小于基准的元素放置在前子序列中&#xff0…

Wireshark抓包

Wireshark 1 抓包时间显示格式 2 界面显示列设置 3 protocol协议解析 4 过滤器 tcp.port:TCP端口tcp.dstport:TCP目的端口tcp.srcport:TCP源端口udp.port:UDP端口udp.dstport:UDP目的端口udp.srcport:UDP…

HIVE --- 窗口函数

目录 简介 概念 数据准备 聚合函数over partition by子句 order by子句 window子句 窗口函数中的序列函数 ntile rank、dense_rank、row_number LAG、LEAD first_value、last_value 简介 本文主要介绍hive中的窗口函数.hive中的窗口函数和sql中的窗口函数相类似,都…

批量操作文件功能-课后程序(JAVA基础案例教程-黑马程序员编著-第七章-课后作业)

【实验7-1】 批量操作文件功能 任务介绍 1.任务描述 在日常工作中,经常会遇到批量操作系统文件的事情,通常情况下,只能手动重复的完成批量文件的操作,这样很是费时费力。本案例要求编写一个文件管理器,…

(二十六)、项目打包H5+微信小程序+app【uniapp+uinicloud多用户社区博客实战项目(完整开发文档-从零到完整项目)】

1,打包H5发布上线到前端页面托管 1.1 上传所有DBschema和云函数 上传所有DBschema到云服务空间 上传所有云函数到云服务空间 1.2 Hbuilderx基础配置 点击manifest.json文件----web配置: 点击发行—H5 1.3 H5打包完成 使用vscode中的live serve…

【C语言进阶】动态内存管理详解与常见动态内存错误以及柔性数组使用与介绍

​ ​📝个人主页:Sherry的成长之路 🏠学习社区:Sherry的成长之路(个人社区) 📖专栏链接:C语言进阶 🎯长路漫漫浩浩,万事皆有期待 文章目录1.动态内存1.1 概述…

运营级手机直播平台源码 短视频直播带货APP源码

短视频直播带货APP源码 全开源原生直播APP源码 前端:原生APP 安卓端:Java 苹果端:OC 后台:PHP 数据库:Mysql 技术框架:Thinkphp5.1 系统特色功能包括:礼物系统;提现方式&#…

2月 公司来一00后卷王,我们这帮老油条真干不过.....

都说00后躺平了,但是有一说一,该卷的还是卷。这不,我们公司来了个00后,工作没两年,跳槽到我们公司起薪18K,都快接近我了。后来才知道人家是个卷王,从早干到晚就差搬张床到工位睡觉了。 2023年春…

【算法】——并查集

作者:指针不指南吗 专栏:算法篇 🐾或许会很慢,但是不可以停下🐾 文章目录1.思想2.模板3.应用3.1 合并集合3.2 连通块中点的数量1.思想 并查集是一种树型的数据结构,用于处理一些不相交集合的合并及查询问题…

ESP32 Arduino EspNow点对点双向通讯

ESP32 Arduino EspNow点对点双向通讯✨本案例分别采用esp32和esp32C3之间点对点单播无线通讯方式。 🌿esp32开发板 🌾esp32c3开发板 🔧所需库(需要自行导入到Arduino IDE library文件夹中,无法在IDE 管理库界面搜索下载到该库)&am…

【GO】k8s 管理系统项目[前端部分16–前端布局]

【GO】k8s 管理系统项目[前端部分–前端布局] 1. 前端布局 2. Layout 2.1 layout src/layout/Layout.vue <template><div class"common-layout"><el-container><el-side width"200">Aside</el-side><el-container>…

哪些骨传导运动蓝牙耳机好,分享几款不错的骨传导耳机

​骨传导耳机在运动中有很多优势&#xff0c;它是一款不入耳的耳机&#xff0c;适合在跑步、骑行、爬山等运动中使用&#xff0c;如果你是一个爱运动的人&#xff0c;骨传导耳机是不错的选择。由于骨传导技术不需要塞入耳朵中就能听到音乐&#xff0c;所以不会产生任何不适感。…

计算机图形学期末复习笔记

计算机图形学 ch1绪论 1.1计算机图形学及其概念 计算机图形学&#xff08;Computer Graphics&#xff09;是研究怎样利用计算机来生成、处理和显示图形的原理、方法和技术的学科。 cg研究对象是图形 图形的要素 几何&#xff08;轮廓、点、线、面&#xff09;非几何要素&…