java for循环优化_Java for循环优化
小編典典
容易被手工制作的微基準所迷惑-您永遠不知道它們的 實際
測量值。這就是為什么有諸如JMH之類的特殊工具的原因。但是,讓我們分析一下原始的手工基準會發生什么:
static class HDouble {
double value;
}
public static void main(String[] args) {
primitive();
wrapper();
}
public static void primitive() {
long start = System.nanoTime();
for (double d = 0; d < 1000000000; d++) {
}
long end = System.nanoTime();
System.out.printf("Primitive: %.3f s\n", (end - start) / 1e9);
}
public static void wrapper() {
HDouble d = new HDouble();
long start = System.nanoTime();
for (d.value = 0; d.value < 1000000000; d.value++) {
}
long end = System.nanoTime();
System.out.printf("Wrapper: %.3f s\n", (end - start) / 1e9);
}
結果有點類似于您的結果:
Primitive: 3.618 s
Wrapper: 1.380 s
現在重復測試幾次:
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
primitive();
wrapper();
}
}
它變得更加有趣:
Primitive: 3.661 s
Wrapper: 1.382 s
Primitive: 3.461 s
Wrapper: 1.380 s
Primitive: 1.376 s
Wrapper: 1.381 s
Primitive: 1.371 s
Wrapper: 1.372 s
Primitive: 1.379 s
Wrapper: 1.378 s
看來這兩種方法都最終得到了優化。再次運行它,現在記錄JIT編譯器活動: -XX:-TieredCompilation
-XX:CompileOnly=Test -XX:+PrintCompilation
136 1 % Test::primitive @ 6 (53 bytes)
3725 1 % Test::primitive @ -2 (53 bytes) made not entrant
Primitive: 3.589 s
3748 2 % Test::wrapper @ 17 (73 bytes)
5122 2 % Test::wrapper @ -2 (73 bytes) made not entrant
Wrapper: 1.374 s
5122 3 Test::primitive (53 bytes)
5124 4 % Test::primitive @ 6 (53 bytes)
Primitive: 3.421 s
8544 5 Test::wrapper (73 bytes)
8547 6 % Test::wrapper @ 17 (73 bytes)
Wrapper: 1.378 s
Primitive: 1.372 s
Wrapper: 1.375 s
Primitive: 1.378 s
Wrapper: 1.373 s
Primitive: 1.375 s
Wrapper: 1.378 s
注意%在第一次迭代時登錄編譯日志。這意味著這些方法是在OSR
(堆棧替換)模式下編譯的。在第二次迭代中,方法以正常模式重新編譯。從那時起,從第三次迭代開始,原語和包裝器之間的執行速度就沒有區別。
您實際測量的是OSR存根的性能。它通常與應用程序的實際性能無關,因此您不必在意它。
但是問題仍然存在,為什么包裝的OSR存根比原始變量的編譯好?為了找出答案,我們需要深入研究生成的匯編代碼:
-XX:CompileOnly=Test -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly
我將忽略所有不相關的代碼,僅保留編譯循環。
原始:
0x00000000023e90d0: vmovsd 0x28(%rsp),%xmm1
0x00000000023e90d6: vaddsd -0x7e(%rip),%xmm1,%xmm1
0x00000000023e90de: test %eax,-0x21f90e4(%rip)
0x00000000023e90e4: vmovsd %xmm1,0x28(%rsp)
0x00000000023e90ea: vucomisd 0x28(%rsp),%xmm0
0x00000000023e90f0: ja 0x00000000023e90d0
包裝器:
0x00000000023ebe90: vaddsd -0x78(%rip),%xmm0,%xmm0
0x00000000023ebe98: vmovsd %xmm0,0x10(%rbx)
0x00000000023ebe9d: test %eax,-0x21fbea3(%rip)
0x00000000023ebea3: vucomisd %xmm0,%xmm1
0x00000000023ebea7: ja 0x00000000023ebe90
如您所見,“原始”情況會產生許多負載并存儲到堆棧位置,而“包裝器”主要執行寄存器內操作。為什么OSR存根引用堆棧是完全可以理解的:在解釋模式下,局部變量存儲在堆棧中,并使OSR存根與此解釋幀兼容。在“包裝器”情況下,該值存儲在堆中,并且對該對象的引用已緩存在寄存器中。
2020-09-28
總結
以上是生活随笔為你收集整理的java for循环优化_Java for循环优化的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java 获取活动窗口_用Java获取活
- 下一篇: java怎么写算法_关于读写锁算法的Ja