Q_S*_*_SJ 7 java bytecode jvm-bytecode
当我从一些小的java函数中读取jvm字节码时,我发现当一个新的局部变量在操作数堆栈上计算时,假设它将存储在局部变量表中,但通常它会立即加载到操作数堆栈中(仅字面上的字节码).我操作不好,是不必要的操作?
Java编译器倾向于以非常简单和直接的方式编译事物,从而将优化留给JIT.
例如,如果你写x *= 3; x *= 4;,你可能会得到字节码
iload_1
iconst_3
imul
istore_1
iload_1
iconst_4
imul
istore_1
Run Code Online (Sandbox Code Playgroud)
理论上,编译器可以确定存储/加载对是冗余的并将其删除.但是有几个理由不这样做 - 1)这增加了很多复杂性而没有任何好处,因为JIT无论如何都会优化一切2)它使调试变得更难,因为你不再能够访问所有局部变量的值3)如果在此表达式的中间以某种方式抛出异常,则局部变量将具有不正确的值.
看着dspin字节码
Method void dspin()
0 dconst_0 // Push double constant 0.0
1 dstore_1 // Store into local variables 1 and 2
2 goto 9 // First time through don't increment
5 dload_1 // Push local variables 1 and 2
6 dconst_1 // Push double constant 1.0
7 dadd // Add; there is no dinc instruction
8 dstore_1 // Store result in local variables 1 and 2
9 dload_1 // Push local variables 1 and 2
10 ldc2_w #4 // Push double constant 100.0
13 dcmpg // There is no if_dcmplt instruction
14 iflt 5 // Compare and loop if less than (i < 100.0)
17 return // Return void when done
Run Code Online (Sandbox Code Playgroud)
唯一的load后面store是在偏移量9可以看到,偏置9可以通过两个不同的路径到达:(1)从偏移2 goto 9; (2)从偏移8开始依次排列
dload_1将局部变量1和2的值推送到操作数堆栈(由于两个变量double):在第一次尝试进入循环时的情况(1),以及在稍后尝试进入循环时的情况(2)时间点.
有趣的是,在这个例子中,如果你删除所有store并且load程序的行为不会改变.但是,Java编译器通常不会尝试变聪明.它或多或少地直接编译Java代码.在这种情况下,局部变量i直接对应于局部变量1和2.
有关更多信息,请参阅Java Compiler优化.
| 归档时间: |
|
| 查看次数: |
468 次 |
| 最近记录: |