在阅读 JVM 规范时(就像一个人一样),当我遇到 7 个iconst_<i>
操作码时,我感到非常惊讶。毕竟,只有一个字节可以玩。
我很少在我的代码中写 2、3、4 或 5 的字面量。我可以理解为什么 -1、0 和 1 可能会被特殊对待,但让我感到惊讶的是,设计师想要在恰好很小的数字上吹出 4 个宝贵的操作码。
有谁知道这是否有充分的理由?我是否低估了这些好处?
我认为,您的假设是正确的:只是为了使字节码更小,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_0
,iconst_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 bytes
which 保持不变,直到b=127
它也使用bipush
. 这种大小的差异是由于 bipush 有 2 个字节,一个字节操作码,第二个字节立即常量值
双推格式:
bipush
byte
正如您从5: bipush 6
字节码中的行中看到的那样,iconst_<n>
仅使用 1 个字节。
所以对一些常用推送的数字定义了这样的字节码,以提高字节码执行的效率,减少字节码流的大小。
正如塔吉尔所说,这些数字的使用频率会比你想象的要多