为什么java字节码"store"后面经常跟"load"?



当我读取JVM字节码时,从某个小Java函数中,当将新的本地变量插入操作数堆栈上时,假设它将存储在局部变量表中,则但是通常,它会立即将其加载到操作数堆栈(实际上是按字节码的术语)。我不太了解操作,这是不必要的操作吗?

Java编译器倾向于以非常简单明了的方式编译事物,将优化留给了JIT。

例如,如果您编写x *= 3; x *= 4;,则可能会沿着

的行获得字节。
iload_1
iconst_3
imul
istore_1
iload_1
iconst_4
imul
istore_1

编译器理论上可以弄清楚商店/负载对是冗余并将其删除。但是有几个原因不这样做的原因 - 1)这增加了很多复杂性,没有利益,因为JIT优化了一切2)它使调试变得更加困难,因为您不再可以访问所有本地变量的值3)如果以某种方式在此表达式的中间放置例外,则局部变量将具有不正确的值。

查看 dspin bytecode

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

store以下唯一的load是在Offset 9中。您可以看到,可以通过两个不同的路径来达到偏移9:(1)从offset 2带有 goto 9;(2)从偏移8

依次

dload_1将局部变量1和2的值推到操作数堆栈上(由于double的两个变量):在(1)尝试第一次尝试输入循环时,在试图(2)时在以后的时间点输入循环。

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

有关更多信息,请参见Java编译器的优化。

请参阅,JVM中的每个操作都在操作数堆栈上完成。因此,每当您必须对变量上执行任何操作,就必须先通过 load load命令在操作数堆栈上(按下)命令,然后执行操作。

这就是为什么 store 之后是 load bytecode中的指令。

相关内容

  • 没有找到相关文章

最新更新