Java字节码中的堆栈=4。Java编译器如何计算4值?(堆栈的深度)

Java字节码中的堆栈=4。Java编译器如何计算4值?(堆栈的深度),java,jvm,javac,bytecode,javap,Java,Jvm,Javac,Bytecode,Javap,Java代码: public class SimpleRecursion { public int factorial(int n) { if (n == 0) { return 1; } return n * factorial(n - 1); } } 给出阶乘方法的以下字节码(我执行javap生成它): 我知道在上面块的第五行中,stack=4表示堆栈最多可以有4个对象 但是编译器是如何计算的呢?由

Java代码:

public class SimpleRecursion {

    public int factorial(int n) {
        if (n == 0) {
            return 1;
        }
        return n * factorial(n - 1);
    }

}
给出阶乘方法的以下字节码(我执行javap生成它):

我知道在上面块的第五行中,stack=4表示堆栈最多可以有4个对象


但是编译器是如何计算的呢?

由于堆栈的初始状态以及每条指令对堆栈的影响是众所周知的,因此您可以精确地预测,在任何时候操作数堆栈上将出现哪种类型的项:

[ ]            // 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堆栈条目维护动态增长的数据结构或预先分配内存。使用声明的最大大小,它可以在遇到将推送超过该大小的指令时停止,因此它永远不需要比声明的内存更多的内存

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

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


此结构将用于生成生成的字节码,它还可以预测该级别上所需的堆栈大小。但是编译器的实际操作方式取决于实现。

显然不是,因为在您的示例中,VIT还计算iconst、isub、ifne等指令。还不清楚您要问什么-当然,要计算堆栈深度,需要计算代码分支中操纵堆栈的所有指令,编写一个方法,但不一定是最终形式,但更可能的是,代码仍处于内部树结构中。谢谢@ErwinBolwidt,我编辑了这个问题,以删除关于iload/aload的混淆部分。
[ ]            // 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