6

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

我很少在我的代码中写 2、3、4 或 5 的字面量。我可以理解为什么 -1、0 和 1 可能会被特殊对待,但让我感到惊讶的是,设计师想要在恰好很小的数字上吹出 4 个宝贵的操作码。

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

4

2 回答 2

6

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

int[] a = {10, 20, 30, 40};

实际上,它被编译为:

int[] a = new int[4];
a[0] = 10;
a[1] = 20;
a[2] = 30;
a[3] = 40;

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

于 2015-06-10T03:16:31.960 回答
4

希望这可以澄清您的问题为什么要浪费 4 Opcode ..

查看此代码的字节码

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

字节码的一部分

0: bipush        20
 2: istore_1
 3: iconst_5
 4: istore_2
 5: bipush        6
 7: istore_3

正如您所看到的,它开始使用大于 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;

    }

}

大小 406 字节

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

双推格式:

bipush
byte

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

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

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

于 2015-06-10T04:26:54.263 回答