什么是什么,是StackOverflowError什么导致它,我应该如何处理它们?
stack-overflow memory-leaks exception-handling out-of-memory
为了估计最大调用深度,递归方法可以用给定量的存储器实现,在堆栈溢出错误可能发生之前计算所用存储器的(近似)公式是什么?
许多人回答"它依赖",这是合理的,所以让我们通过使用一个微不足道但具体的例子来删除一些变量:
public static int sumOneToN(int n) {
return n < 2 ? 1 : n + sumOneToN(n - 1);
}
Run Code Online (Sandbox Code Playgroud)
很容易证明,在我的Eclipse IDE中运行它会爆炸n不到1000(对我来说非常低).这个调用深度限制是否可以在不执行的情况下估算?
编辑:我不禁认为Eclipse有一个固定的最大调用深度1000,因为我得到了998,但是有一个用于main,一个用于初始调用方法,1000总而言之.这是一个"太圆"的数字恕我直言,是一个巧合.我会进一步调查.我只是Dux开销-Xss vm参数; 它是最大的堆栈大小,所以Eclipse运行器必须-Xss1000设置在某处
用于演示目的的简单类:
public class Main {
private static int counter = 0;
public static void main(String[] args) {
try {
f();
} catch (StackOverflowError e) {
System.out.println(counter);
}
}
private static void f() {
counter++;
f();
}
}
Run Code Online (Sandbox Code Playgroud)
我执行了5次上面的程序,结果是:
22025
22117
15234
21993
21430
Run Code Online (Sandbox Code Playgroud)
为什么结果每次都不同?
我尝试设置最大堆栈大小(例如-Xss256k).然后结果更加一致,但每次都不相等.
Java版本:
java version "1.8.0_72"
Java(TM) SE Runtime Environment (build 1.8.0_72-b15)
Java HotSpot(TM) 64-Bit Server VM (build 25.72-b15, mixed mode)
Run Code Online (Sandbox Code Playgroud)
编辑
当JIT被禁用时(-Djava.compiler=NONE)我总是得到相同的数字(11907).
这是有道理的,因为JIT优化可能会影响堆栈帧的大小,并且JIT完成的工作肯定必须在执行之间变化.
尽管如此,我认为如果通过参考关于该主题的一些文档和/或JIT在这个特定示例中完成的工作的具体示例来确认该理论将导致框架大小改变将是有益的.
据Oracle称,StackOverflowError是:
在发生堆栈溢出时抛出,因为应用程序过于严重.
我知道递归是什么,通常递归函数,如果没有正确终止,会导致StackOverflowError.为了检查StackOverflowError抛出之前发生的递归调用的数量,我写了这段代码:
package ErrorCases;
public class StackOverFlowError {
static int i=0;
void a()
{
//System.out.println("called "+(++i));
try{
++i;
a();
}catch(Error e)
{
System.out.println(e.getClass());
System.out.println(i);
}
}
public static void main(String[] args) {
new StackOverFlowError().a();
}
}
Run Code Online (Sandbox Code Playgroud)
在JVM抛出StackOverflowError之前,i给出递归调用计数的值a().每次运行
的价值i都不同,如:
output 1: class java.lang.StackOverflowError
10466
Output 2: class java.lang.StackOverflowError
10470
Run Code Online (Sandbox Code Playgroud)
我的疑问是?
在JVM抛出之前递归有多深
StackOverflowError?
一旦StackOverflowError投掷,我们可以恢复吗?