深入理解编译优化之循环展开和粗化锁
文章目录
- 简介
- 循环展开和粗化锁
- 分析Assembly日志
- 禁止Loop unrolling
- 总结
简介
之前在讲JIT的时候,有提到在编译过程中的两种优化循环展开和粗化锁,今天我们和小师妹一起从Assembly的角度来验证一下这两种编译优化方法,快来看看吧。
循环展开和粗化锁
小师妹:F师兄,上次你讲到在JIT编译的过程中会进行一些编译上面的优化,其中就有循环展开和粗化锁。我对这两种优化方式很感兴趣,能不能展开讲解一下呢?
当然可以,我们先来回顾一下什么是循环展开。
更多精彩内容且看:
- 区块链从入门到放弃系列教程-涵盖密码学,超级账本,以太坊,Libra,比特币等持续更新
- Spring Boot 2.X系列教程:七天从无到有掌握Spring Boot-持续更新
- Spring 5.X系列教程:满足你对Spring5的一切想象-持续更新
- java程序员从小工到专家成神之路(2020版)-持续更新中,附详细文章教程
循环展开就是说,像下面的循环遍历的例子:
for (int i = 0; i < 1000; i++) {x += 0x51;}
因为每次循环都需要做跳转操作,所以为了提升效率,上面的代码其实可以被优化为下面的:
for (int i = 0; i < 250; i++) {x += 0x144; //0x51 * 4}
注意上面我们使用的是16进制数字,至于为什么要使用16进制呢?这是为了方便我们在后面的assembly代码中快速找到他们。
好了,我们再在 x += 0x51 的外面加一层synchronized锁,看一下synchronized锁会不会随着loop unrolling展开的同时被粗化。
for (int i = 0; i < 1000; i++) {synchronized (this) {x += 0x51;}}
万事具备,只欠我们的运行代码了,这里我们还是使用JMH来执行。
相关代码如下:
@Warmup(iterations = 10, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
@Fork(value = 1,jvmArgsPrepend = {"-XX:-UseBiasedLocking","-XX:CompileCommand=print,com.flydean.LockOptimization::test"
})
@State(Scope.Benchmark)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public class LockOptimization {int x;@Benchmark@CompilerControl(CompilerControl.Mode.DONT_INLINE)public void test() {for (int i = 0; i < 1000; i++) {synchronized (this) {x += 0x51;}}}public static void main(String[] args) throws RunnerException {Options opt = new OptionsBuilder().include(LockOptimization.class.getSimpleName()).build();new Runner(opt).run();}
}
上面的代码中,我们取消了偏向锁的使用:-XX:-UseBiasedLocking。为啥要取消这个选项呢?因为如果在偏向锁的情况下,如果线程获得锁之后,在之后的执行过程中,如果没有其他的线程访问该锁,那么持有偏向锁的线程则不需要触发同步。
为了更好的理解synchronized的流程,这里我们将偏向锁禁用。
其他的都是我们之前讲过的JMH的常规操作。
接下来就是见证奇迹的时刻了。
分析Assembly日志
我们运行上面的程序,将会得到一系列的输出。因为本文并不是讲解Assembly语言的,所以本文只是大概的理解一下Assembly的使用,并不会详细的进行Assembly语言的介绍,如果有想深入了解Assembly的朋友,可以在文后留言。
分析Assembly的输出结果,我们可以看到结果分为C1-compiled nmethod和C2-compiled nmethod两部分。
先看C1-compiled nmethod:
第一行是monitorenter,表示进入锁的范围,后面还跟着对于的代码行数。
最后一行是monitorexit,表示退出锁的范围。
中间有个add $0x51,%eax操作,对于着我们的代码中的add操作。
可以看到C1—compiled nmethod中是没有进行Loop unrolling的。
我们再看看C2-compiled nmethod:
和C1很类似,不同的是add的值变成了0x144,说明进行了Loop unrolling,同时对应的锁范围也跟着进行了扩展。
最后看下运行结果:
Benchmark Mode Cnt Score Error Units
LockOptimization.test avgt 5 5601.819 ± 620.017 ns/op
得分还不错。
禁止Loop unrolling
接下来我们看下如果将Loop unrolling禁掉,会得到什么样的结果。
要禁止Loop unrolling,只需要设置-XX:LoopUnrollLimit=1即可。
我们再运行一下上面的程序:
可以看到C2-compiled nmethod中的数字变成了原本的0x51,说明并没有进行Loop unrolling。
再看看运行结果:
Benchmark Mode Cnt Score Error Units
LockOptimization.test avgt 5 20846.709 ± 3292.522 ns/op
可以看到运行时间基本是优化过后的4倍左右。说明Loop unrolling还是非常有用的。
总结
本文介绍了循环展开和粗化锁的实际例子,希望大家能够喜欢。
本文的例子https://github.com/ddean2009/learn-java-base-9-to-20
本文作者:flydean程序那些事
本文链接:http://www.flydean.com/jvm-jit-loop-unrolling-lock-coarsening/
本文来源:flydean的博客
欢迎关注我的公众号:程序那些事,更多精彩等着您!
深入理解编译优化之循环展开和粗化锁相关推荐
- 小师妹学JVM之:深入理解JIT和编译优化-你看不懂系列
文章目录 简介 JIT编译器 Tiered Compilation分层编译 OSR(On-Stack Replacement) Deoptimization 常见的编译优化举例 Inlining内联 ...
- delete优化_深入理解JIT和编译优化
点击上方的蓝字关注我吧 程序那些事 简介 小师妹已经学完JVM的简单部分了,接下来要进入的是JVM中比较晦涩难懂的概念,这些概念是那么的枯燥乏味,甚至还有点惹人讨厌,但是要想深入理解JVM,这些概念是 ...
- 你真的了解java编译优化吗?15个问题考察自己是否理解
[摘要] 早期编译过程 晚期编译优化 jvm编译优化学习笔记 早期 第一步: -------词法分析: -------语法分析(注意实际上只是生成一个语法树,还没做语法的校验): -------填充符 ...
- 编译优化 | LLVM代码生成技术详解及在数据库中的应用
简介:作者:长别 1. 前言 随着IT基础设施的发展,现代的数据处理系统需要处理更多的数据.支持更为复杂的算法.数据量的增长和算法的复杂化,为数据分析系统带来了严峻的性能挑战.近年来,我们可以在数据库 ...
- 并发高?可能是编译优化引发有序性问题
摘要:CPU为了对程序进行优化,会对程序的指令进行重排序,此时程序的执行顺序和代码的编写顺序不一定一致,这就可能会引起有序性问题. 本文分享自华为云社区<[高并发]解密导致并发问题的第三个幕后黑 ...
- 15个问题自查你真的了解java编译优化吗?
摘要:为什么C++的编译速度会比java慢很多?二者运行程序的速度差异在哪? 了解了java的早期和晚期过程,就能理解这个问题了. 本文分享自华为云社区<你真的了解java编译优化吗?15个问题 ...
- supersu二进制更新安装失败_Q音直播编译优化与二进制集成方案
一.背景: Q音直播抽离成pod库分别引入到QQ音乐和Fan直播两个独立app中,而对于直播业务来讲,直播SDK通过pod本地引入集成到Demo中进行日常直播业务的开发,通过Demo来精简工程规模,提 ...
- 打印异常堆栈_通过异常堆栈丢失谈即时编译优化
前言 日照充足会让西瓜更甜,那拥有即时编译优化会让Java程序怎么样?本文会初步介绍JVM的即时编译优化特性,并且通过异常堆栈丢失这一常见的现象来进行举例 即时编译优化 Java程序在运行初期是通过解 ...
- c++ 输出二进制_Q音直播编译优化与二进制集成方案
一.背景: Q音直播抽离成pod库分别引入到QQ音乐和Fan直播两个独立app中,而对于直播业务来讲,直播SDK通过pod本地引入集成到Demo中进行日常直播业务的开发,通过Demo来精简工程规模,提 ...
最新文章
- Android在桌面上添加开关,多键开关 Andromax v1.1.7
- ITK:仅将过滤器应用于图像的指定区域
- std::bind 详解及参数解析
- Java构造函数的深入理解
- 查询数据库中有多少个数据表_您的数据中有多少汁?
- mysql: you can't specify target table 问题解决
- Java屏蔽输入法_技巧:如何禁止输入法切换到全角状态
- sudo报错案例-RHEL6
- 【CODEVS1191】数轴染色
- linux内核源码分析--内核启动之,Linux内核源码分析之setup_arch (二)
- html消息对话框,添加消息对话框 (HTML)
- 从X86架构来源开始:谈CPU
- 计算机硬件软件的学习
- 请问:现正在广告上的丰胸产物是不是实的?
- 常用数据库的基因ID
- linux 进程调度cfg,选择Linux I / O调度程序
- 经常玩电脑正确的坐姿_细说用电脑的正确坐姿
- 元素被鼠标掠过控制另一个元素显隐
- docker常用命令-docker start
- Linux下离线安装Google Chrome