递归方法调用的哪些部分对堆栈有贡献 - 比如返回的对象,参数,局部变量等等?
我正在尝试优化Android应用程序在运行到StackOverflowException之前可以在有限内存上执行的递归级别。
提前致谢。
答案 0 :(得分:0)
如果您的堆栈空间不足,请不要优化堆栈使用情况。这样做意味着同样的问题将在稍后回来,输入设置稍大或从其他地方调用。在某些时候,你已达到理论或实际的最小空间,你可以为你正在解决的问题消耗。相反,将有问题的代码转换为使用除机器堆栈之外的集合(例如,堆分配的堆栈或队列)。这样做有时会导致非常难看的代码,但至少它不会崩溃。
但要回答这个问题:通常你所命名的所有内容都可以占用堆栈空间,临时值也占用空间(因此嵌套表达式就像疯了一样只是为了保存局部变量无济于事)。其中一些将存储在寄存器中,具体取决于调用约定,但无论如何都可能必须溢出(*)。但是无论调用约定如何,这只会节省几个字节,并且所有内容都必须为调用溢出,因为调用者通常在调用期间通过寄存器自由统治。因此,当堆栈溢出时,堆栈确实拥挤了早期调用的参数,局部变量和临时值。有些可能完全被优化掉或者如果不同时需要共享堆栈槽。最终,这取决于JIT编译器。
(*)Spilling:将值从寄存器移到内存(即堆栈),因为其他东西需要寄存器。
答案 1 :(得分:0)
每个方法都有两个与之关联的堆栈帧大小,参数和局部变量所需的堆栈,以及表达式求值所需的堆栈。返回值仅计为表达式求值所需的堆栈的一部分。 JVM能够在执行时验证方法是否超过这些大小。
变量需要多少堆栈,表达式评估归结为字节码编译器。例如,它通常能够在具有非重叠生存期的变量之间共享局部变量槽。