2017-03-14 51 views
5

当我从一些小的java函数中读取jvm字节码时,我发现当一个新的局部变量被计算在操作数堆栈上时,假设它将被存储在局部变量表中,但通常它会被加载到操作数立即堆栈(就字面字节而言)。我不太了解操作,这是不必要的操作吗?为什么java字节码“store”后面经常会出现“load”?

+0

请举例。很难说,否则你在说什么。不可能,真的。 – EJP

+0

请详细说明您的问题。 –

+0

你不可能在评论中令人满意地回答这个问题。将它编辑到你的问题中,它应该放在首位。 – EJP

回答

6

Java编译器倾向于以一种非常简单直接的方式编译事物,并将优化留给JIT。

例如,如果你写x *= 3; x *= 4;,你可能会得到字节码沿

iload_1 
iconst_3 
imul 
istore_1 
iload_1 
iconst_4 
imul 
istore_1 

编译器的线在理论上弄清楚,商店/对负载是多余的,将其删除。但有几个理由不这样做 - 1)这增加了很多复杂性,因为JIT无论如何优化了所有内容2)它使调试变得更加困难,因为您不再能够访问所有局部变量的值3)如果在该表达式的中间以某种方式抛出异常,则局部变量将具有不正确的值。

4

综观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 

唯一load下面store是在偏移量9可以看到,偏置9可以通过两个不同的路径到达:(1)从偏移2与goto 9;和(2)从偏移量开始顺序8

dload_1将局部变量1和2的值推送到操作数堆栈(两个变量因为double):如果(1)第一次尝试进入循环时, (2)在稍后的时间点尝试进入循环时。

有趣的是,在本例中,如果您删除所有storeload,程序的行为不会改变。但是,Java编译器通常不会很聪明。它或多或少地直接编译Java代码。在这种情况下,局部变量i直接对应于局部变量1和2.

请参阅Optimization by Java Compiler了解更多信息。

+0

如果我删除所有'store'和'load',那么上面的代码是否仍然可以工作? –

+0

@Q_SJ,请参阅编辑答案。 – dejvuth

+0

如果我正确理解你,你的意思是在某些情况下,javac确实会生成一对“存储”和“加载”。我对吗? –

相关问题