JVM 的人为限制为 1024 个条目,您可以在异常或错误的堆栈跟踪中拥有这些条目,这可能是为了在发生异常或错误时节省内存(因为 VM 必须分配内存来存储堆栈跟踪)。
幸运的是,有一个标志允许增加此限制。只需使用以下参数运行程序:
-XX:MaxJavaStackTraceDepth=1000000
这将打印多达 100 万个堆栈跟踪条目,这应该绰绰有余。也可以将此值设置为 at,以将条目数设置为无限制。0
此非标准 JVM 选项列表提供了更多详细信息:
最大编号堆栈跟踪中 Java 异常的行数(0 表示全部)。对于 Java > 1.6,值 0 实际上表示 0。必须指定值 -1 或任何负数才能打印所有堆栈(在 Windows 上使用 1.6.0_22、1.7.0 进行测试)。对于Java <= 1.5,值0表示一切,JVM扼流于负数(在Windows上使用1.5.0_22测试)。
使用此标志运行问题示例会得到以下结果:
Exception in thread "main" java.lang.StackOverflowError
at Overflow.<init>(Overflow.java:3)
at Overflow.<init>(Overflow.java:4)
at Overflow.<init>(Overflow.java:4)
at Overflow.<init>(Overflow.java:4)
(more than ten thousand lines later:)
at Overflow.<init>(Overflow.java:4)
at Overflow.<init>(Overflow.java:4)
at Overflow.a(Overflow.java:7)
at Overflow.main(Overflow.java:10)
这样,即使实际的堆栈跟踪长度超过 1024 行,也可以找到引发 Error 的代码的原始调用方。
如果您无法使用该选项,那么还有另一种方法,如果您处于这样的递归函数中,并且如果您可以修改它。如果添加以下尝试捕获:
public Overflow() {
try {
new Overflow();
}
catch(StackOverflowError e) {
StackTraceElement[] stackTrace = e.getStackTrace();
// if the stack trace length is at the limit , throw a new StackOverflowError, which will have one entry less in it.
if (stackTrace.length == 1024) {
throw new StackOverflowError();
}
throw e; // if it is small enough, just rethrow it.
}
}
从本质上讲,这将创建并抛出一个新的,丢弃最后一个条目,因为与前一个条目相比,每个条目都会被发送一个级别(这可能需要几秒钟,因为必须创建所有这些错误)。当堆栈跟踪将减少到 1023 个元素时,只需将其重新推。StackOverflowError
最终,这将在堆栈跟踪的底部打印 1023 行,这不是完整的堆栈跟踪,但可能是其中最有用的部分。