san*_*ity 42 java optimization jit compiler-optimization
在最近关于如何优化某些代码的讨论中,我被告知将代码分解为许多小方法可以显着提高性能,因为JIT编译器不喜欢优化大型方法.
我不确定这一点,因为看起来JIT编译器本身应该能够识别自包含的代码段,而不管它们是否在他们自己的方法中.
任何人都可以确认或驳斥这一说法吗?
ass*_*ias 30
Hotspot JIT仅内联小于特定(可配置)大小的方法.因此,使用较小的方法可以实现更多的内联,这是很好的.
请参阅此页面上的各种内联选项.
编辑
详细说明:
示例(如果您尝试,则完整代码具有相同的行号)
package javaapplication27;
public class TestInline {
private int count = 0;
public static void main(String[] args) throws Exception {
TestInline t = new TestInline();
int sum = 0;
for (int i = 0; i < 1000000; i++) {
sum += t.m();
}
System.out.println(sum);
}
public int m() {
int i = count;
if (i % 10 == 0) {
i += 1;
} else if (i % 10 == 1) {
i += 2;
} else if (i % 10 == 2) {
i += 3;
}
i += count;
i *= count;
i++;
return i;
}
}
Run Code Online (Sandbox Code Playgroud)
使用以下JVM标志运行此代码时:( -XX:+UnlockDiagnosticVMOptions -XX:+PrintCompilation -XX:FreqInlineSize=50 -XX:MaxInlineSize=50 -XX:+PrintInlining是的,我使用了证明我的情况的值:m太大但重构m并且m2低于阈值 - 使用其他值可能会得到不同的输出).
您将看到m()并main()编译,但m()不会内联:
56 1 javaapplication27.TestInline::m (62 bytes)
57 1 % javaapplication27.TestInline::main @ 12 (53 bytes)
@ 20 javaapplication27.TestInline::m (62 bytes) too big
Run Code Online (Sandbox Code Playgroud)
您还可以检查生成的程序集以确认m未内联(我使用了这些JVM标志:) -XX:+PrintAssembly -XX:PrintAssemblyOptions=intel- 它将如下所示:
0x0000000002780624: int3 ;*invokevirtual m
; - javaapplication27.TestInline::main@20 (line 10)
Run Code Online (Sandbox Code Playgroud)
如果你像这样重构代码(我在一个单独的方法中提取了if/else):
public int m() {
int i = count;
i = m2(i);
i += count;
i *= count;
i++;
return i;
}
public int m2(int i) {
if (i % 10 == 0) {
i += 1;
} else if (i % 10 == 1) {
i += 2;
} else if (i % 10 == 2) {
i += 3;
}
return i;
}
Run Code Online (Sandbox Code Playgroud)
您将看到以下编译操作:
60 1 javaapplication27.TestInline::m (30 bytes)
60 2 javaapplication27.TestInline::m2 (40 bytes)
@ 7 javaapplication27.TestInline::m2 (40 bytes) inline (hot)
63 1 % javaapplication27.TestInline::main @ 12 (53 bytes)
@ 20 javaapplication27.TestInline::m (30 bytes) inline (hot)
@ 7 javaapplication27.TestInline::m2 (40 bytes) inline (hot)
Run Code Online (Sandbox Code Playgroud)
因此,您可以期待m2内联m,这样我们就可以回到最初的场景.但是当main编译时,它实际上是整个内容.在装配级别,这意味着您将不再找到任何invokevirtual指令.你会发现这样的行:
0x00000000026d0121: add ecx,edi ;*iinc
; - javaapplication27.TestInline::m2@7 (line 33)
; - javaapplication27.TestInline::m@7 (line 24)
; - javaapplication27.TestInline::main@20 (line 10)
Run Code Online (Sandbox Code Playgroud)
基本上常见的指令是"共同的".
结论
我并不是说这个例子具有代表性,但似乎证明了几点:
最后:如果您的代码的一部分对于这些考虑因素至关重要的性能至关重要,那么您应该检查JIT输出以微调您的代码并重要地分析前后的配置文件.
我不太明白它是如何工作的,但根据AurA 提供的链接,我猜测如果重用相同的位,JIT 编译器将不得不编译更少的字节码,而不是必须编译跨域相似的不同字节码不同的方法。
除此之外,你越能够将代码分解成有意义的片段,你就能从代码中获得更多的重用,这将允许优化运行它的虚拟机(你提供了更多的模式)跟...共事)。
但是,我怀疑如果您在没有任何意义且不提供代码重用的情况下分解代码,是否会产生任何良好的影响。
| 归档时间: |
|
| 查看次数: |
3399 次 |
| 最近记录: |