25 | 循环优化
郑雨迪
该思维导图由 AI 生成,仅供参考
在许多应用程序中,循环都扮演着非常重要的角色。为了提升循环的运行效率,研发编译器的工程师提出了不少面向循环的编译优化方式,如循环无关代码外提,循环展开等。
今天,我们便来了解一下,Java 虚拟机中的即时编译器都应用了哪些面向循环的编译优化。
循环无关代码外提
所谓的循环无关代码(Loop-invariant Code),指的是循环中值不变的表达式。如果能够在不改变程序语义的情况下,将这些循环无关代码提出循环之外,那么程序便可以避免重复执行这些表达式,从而达到性能提升的效果。
举个例子,在上面这段代码中,循环体中的表达式x*y,以及循环判断条件中的a.length均属于循环不变代码。前者是一个整数乘法运算,而后者则是内存访问操作,读取数组对象a的长度。(数组的长度存放于数组对象的对象头中,可通过 arraylength 指令来访问。)
理想情况下,上面这段代码经过循环无关代码外提之后,等同于下面这一手工优化版本。
我们可以看到,无论是乘法运算x*y,还是内存访问a.length,现在都在循环之前完成。原本循环中需要执行这两个表达式的地方,现在直接使用循环之前这两个表达式的执行结果。
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
- 深入了解
- 翻译
- 解释
- 总结
即时编译器中的循环优化是提升性能的重要手段。本文介绍了Java虚拟机中的循环优化技术,包括循环无关代码外提、循环展开、循环判断外提和循环剥离。循环无关代码外提通过提取循环中不变的表达式,避免重复计算以提升性能。循环展开通过重复多次循环迭代并减少循环次数来优化代码。循环判断外提将循环中的if语句提出至循环之前,以优化执行路径。循环剥离则是将循环的前几个或后几个迭代剥离出循环,以触发进一步优化。文章还提到了循环展开的特殊情况——完全展开,以及循环优化的实践案例。总的来说,本文深入介绍了即时编译器中的循环优化技术,对于理解编译器优化和性能提升具有一定的参考价值。
仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《深入拆解 Java 虚拟机》,新⼈⾸单¥59
《深入拆解 Java 虚拟机》,新⼈⾸单¥59
立即购买
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
登录 后留言
全部留言(14)
- 最新
- 精选
- 钱现在浏览器终于也可以写留言了,非常好!希望能将和老师相互的讨论的功能也开开,否则,不能进行对话,讲某些问题的效果不太好! 循环优化,站在编译器的角度来作出的优化动作,老师介绍了几种方式,经过听讲,我感觉万变不离其宗,优化的核心关键点还是少做一些事情,当然,事情少做了,作用不能减! 1:循环无关码外提——将循环内的某些无关代码外移,减少某些程序的反复执行 2:循环展开——减少循环条件的判断,针对循环次数少的循环 3:循环判断外提——减少每次循环的都进行判断次数 4:循环剥离——将不通用的处理起来稍微费劲一些的动作,放在循环外处理 总之,要做减法! 性能优化的核心点: 1:让做的快的做 2:如果不能实现,则让做的快的做多一点,做的慢的少做一些 3:取巧,事情少做了,但是目的依旧能够达到
作者回复: 对的。在程序语义不改变的情况下,编译器会尽可能地减少生成代码的工作量。
2018-09-1729 - Geek_488a8e这些都是DSP代码典型的优化方法,目的是防止打断CPU的指令流水,提高指令处理的并行度
作者回复: Good to know
2018-09-19323 - Len老师,如果有这样一段代码: for( ... ) { sum += x + y + a[i]; } 借助 Sea-of-Nodes IR 能把「x + y」表达式外提出去。 但,如果表达式变成如下: sum += x + a[i] + y; 也能借助 IR 外提 「x + y」吗?
作者回复: 赞想法!会的。
2018-09-1814 - 一个坏人是不是写应用系统的时候没必要按照优化方式写,编译器反正会优化?!
作者回复: 很多情况下是的。但也要考虑编译器没有预算来做优化的情况(比如循环太大)。 一般来说,应用代码更应注重可读性。
2018-09-176 - Scott这样展开后有一个强度削弱的机会,四个byte的赋值合并成一个int?
作者回复: 对的!不叫强度削弱,叫向量化,下一篇讲
2018-09-173 - 饭粒有点像小学四则运算里运用提公因式法等技巧来使计算简单。
作者回复: 哈哈,确实像
2019-12-252 - Leon Wong请问老师,实践环节的循环展开后的数组越界,编译器是怎么处理的?是不是当length小于4,循环完全展开就可以了,实际上这个展开有一个隐含的假定,即length大于4的情况。
作者回复: 对的,如果是常量长度,而且小于4,那么完全展开就行了。
2018-10-07 - 白三岁实践环节的代码,由于i++相应的变成了i+4。前面的判断条件dst.length就不应该减4了吧。
作者回复: 观察到位!这个主要是为了避免访问越界。你可以假定length为3,再看看这段代码。
2018-09-28 - 无言的约定for (int i = INIT; i < LIMIT; i += STRIDE) { if (i < 0 || i >= a.length) { // range check throw new ArrayIndexOutOfBoundsException(); } sum += a[i]; } ---------- // 经过下标范围检测外提之后: if (INIT < 0 || IMAX >= a.length) { // IMAX 是 i 所能达到的最大值,注意它不一定是 LIMIT-1 detopimize(); // never returns } for (int i = INIT; i < LIMIT; i += STRIDE) { sum += a[i]; // 不包含下标范围检测 } 老师,这个IMAX该如何初始化?2019-10-121
- 天之蓝请教两个问题,循环展开那个例子如果64是65是不是就越界了?实践的代码如果length为6按条件只会循环一次那下标为4、5的不就执行不到了吗?2018-11-281
收起评论