为了账号安全,请及时绑定邮箱和手机立即绑定

Java 字节码中的 Stack=4。Java 编译器如何计算 4 的值?

Java 字节码中的 Stack=4。Java 编译器如何计算 4 的值?

慕斯709654 2022-05-21 20:43:18
Java 代码:public class SimpleRecursion {    public int factorial(int n) {        if (n == 0) {            return 1;        }        return n * factorial(n - 1);    }}为阶乘方法提供以下字节码(我执行 javap 来生成它):public int factorial(int); descriptor: (I)I flags: ACC_PUBLIC Code:     stack=4, locals=2, args_size=2     0: iload_1     1: ifne          6     4: iconst_1     5: ireturn     6: iload_1     7: aload_0     8: iload_1     9: iconst_1    10: isub    11: invokevirtual #2                  // Method factorial:(I)I    14: imul    15: ireturn     LineNumberTable:    line 4: 0    line 5: 4    line 7: 6     StackMapTable: number_of_entries = 1    frame_type = 6 /* same */我知道在上面块的第五行中,stack=4 意味着堆栈最多可以有 4 个 objects。但是编译器是如何计算的呢?
查看完整描述

1 回答

?
12345678_0001

TA贡献1802条经验 获得超5个赞

由于栈的初始状态,以及每条指令对它的影响是众所周知的,你可以精确地预测,在任何时候,操作数栈上会出现什么样的项:


[ ]            // initially empty

[ I ]          0: iload_1

[ ]            1: ifne          6

[ I ]          4: iconst_1

[ ]            5: ireturn

[ I ]          6: iload_1

[ I O ]        7: aload_0

[ I O I ]      8: iload_1

[ I O I I ]    9: iconst_1

[ I O I ]     10: isub

[ I I ]       11: invokevirtual #2   // Method factorial:(I)I

[ I ]         14: imul

[ ]           15: ireturn   

JVM 的验证器会这样做,在每条指令之后预测堆栈的内容,以检查它是否适合作为后续指令的输入。但它在这里有帮助,有一个声明的最大大小,所以验证器不需要维护一个动态增长的数据结构或为理论上可能的 64k 堆栈条目预分配内存。使用声明的最大大小,它可以在遇到会推送更多的指令时停止,因此它永远不需要比声明更多的内存。


如您所见,声明的最大堆栈大小恰好iconst_1在索引 9 处的指令之后达到一次。


然而,这并不意味着编译器必须执行这样的指令分析。编译器具有从源代码派生的代码的更高级别模型,称为抽象语法树。


该结构将用于生成生成的字节码,并且它还可能已经能够预测该级别所需的堆栈大小。但是编译器实际上是如何做到的,是依赖于实现的。


查看完整回答
反对 回复 2022-05-21
  • 1 回答
  • 0 关注
  • 141 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信