为什么JVM有iconst_2 - iconst_5操作码?

use*_*642 6 java jvm opcodes

在阅读JVM规范时(就像我一样),当我遇到7个iconst_<i>操作码时,我感到非常惊讶.毕竟,只有一个字节可以播放.

我很少在代码中写入2,3,4或5的文字.我可以理解为什么-1,0和1可能会被特别对待,但我觉得设计师想要将4个珍贵的操作码吹到恰好相当小的数字上似乎很神奇.

有谁知道这是否有充分理由?我低估了这些的好处吗?

Tag*_*eev 5

我认为,您的假设是正确的:只是为了使字节码更小而Java解释器稍微快一点(那些时候没有JIT编译器)。请注意,这些字节码的使用频率可能比您期望的要高得多。例如,考虑以下代码:

int[] a = {10, 20, 30, 40};
Run Code Online (Sandbox Code Playgroud)

有效地将其编译为以下内容:

int[] a = new int[4];
a[0] = 10;
a[1] = 20;
a[2] = 30;
a[3] = 40;
Run Code Online (Sandbox Code Playgroud)

因此iconst_0iconst_4即使您在源代码中没有这样的常量,也可以使用这里to 。


Ank*_*and 5

希望这可以澄清你的问题为什么浪费 4 个操作码..

查看此代码的字节码

public static void main(String[] args) {
        int b = 20;
        int c = 5;
        int d= 6;
    }
Run Code Online (Sandbox Code Playgroud)

字节码的一部分

0: bipush        20
 2: istore_1
 3: iconst_5
 4: istore_2
 5: bipush        6
 7: istore_3
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,对于大于 5 的数字,它开始使用的bipush效率通常低于等效数字iconst_<n>,并且还会占用类文件中更多的字节。

bipush byte1扩展byte1为 int 然后将其压入堆栈,因为 Java 堆栈上的每个槽都是 32 位宽(JVM 是基于堆栈的虚拟机)

并查看是否bipush占用更多字节..

查看以下两个代码的类文件大小。(这个大小是在我的 64 位机器上。在您的机器上可能有所不同,但差异是相同的)

public class Test2 {

    public static void main(String[] args) {
        int b = 5;

    }

}
Run Code Online (Sandbox Code Playgroud)

大小 406 字节

现在如果我更换b =6;同一类文件的大小变得407 bytes保持不变,直到即使当b=127它也使用bipush. 这种大小差异是由于 bipush 有 2 个字节,一个字节操作码,第二个字节立即常量值

双推格式:

bipush
byte
Run Code Online (Sandbox Code Playgroud)

正如您从5: bipush 6字节码中的行所看到的, whileiconst_<n>仅使用 1 个字节。

所以针对一些常用的压入的数字定义了这样的字节码,以提高字节码执行效率并减少字节码流的大小。

正如塔吉尔所说,这些数字的使用频率比你想象的要高