为什么在Java字节码方法中使用的局部变量数量不是最经济的?

pf_*_*les 30 java jvm bytecode javac

我有一段简单的Java代码:

public static void main(String[] args) {
    String testStr = "test";
    String rst = testStr + 1 + "a" + "pig" + 2;
    System.out.println(rst);
}
Run Code Online (Sandbox Code Playgroud)

使用Eclipse Java编译器对其进行编译,然后使用AsmTools检查字节码。表明:

字节码

该方法中包含三个局部变量。参数位于插槽0中,并且代码假定使用插槽1和2。但是我认为2个局部变量就足够了-索引0仍然是参数,并且代码仅需要一个变量。

为了查看我的想法是否正确,我编辑了文本字节码,将局部变量的数量减少到2,并调整了一些相关指令:

已编辑

我用AsmTools重新编译了它,效果很好!

那么,为什么Javac或Eclipse编译器不进行这种优化以使用最小局部变量呢?

Ant*_*ony 39

有几个原因。首先,性能不是必需的。JVM已经在运行时进行了优化,因此没有必要在编译器中增加多余的复杂性。

但是,这里没有人提到的另一个主要原因是调试。使字节码与原始源尽可能接近,这使调试变得容易得多。

  • @JustinTime [Oracle似乎不同意](https://docs.oracle.com/en/java/javase/12/vm/java-virtual-machine-technology-overview.html#GUID-982B244A-9B01-479A-8651 -CB6475019281):“自适应编译器:**使用标准解释器启动应用程序。**当应用程序运行时,将对代码进行分析以检测性能瓶颈或热点。JavaHotSpot VM会编译性能关键部分。可以提高性能,但不能编译很少使用的代码(大部分应用程序)**。” (强调我的) (2认同)

Gho*_*ica 24

仅仅是因为Java从即时编译器中获得了性能。

您在Java源代码中所做的事情,甚至类文件中显示的内容,都不是在运行时提高性能的原因。当然,您不应忽略这一部分,而只是要避免在此处做出“愚蠢”的意义。

含义:jvm在运行时决定是否值得将一种方法转换为(高度优化!)机器代码。如果jvm决定“不值得优化”,为什么要在其中进行大量优化来使javac更复杂,更慢?另外:传入的字节码越简单,越基础,JIT就越容易分析和改进该输入!


Lua*_*aan 6

嗯,你只是让之间曾经被认为是两个完全独立的当地人虚假的依赖。这意味着JIT编译器要么需要更复杂/更慢才能解开更改并恢复为原始字节码,要么会受到其可以进行的优化的限制。

请记住,Java编译器在您的开发(或构建)计算机上运行一次。是JIT编译器知道其运行的硬件(和软件)。Java编译器需要创建简单,直接的代码,JIT可以轻松地对其进行处理和优化(或在某些情况下解释)。没有太多理由过度优化字节码本身-您可能会削减可执行文件大小的几个字节,但是为什么要打扰,特别是如果结果是CPU效率较低的代码或更长的JIT编译时间呢?

我现在没有进行实际测试的环境,但是我很确定JIT会从两个字节码中产生相同的可执行代码(它在.NET中确实可以,在许多方面都非常相似)。