When observing a StackOverflowError how to retrieve the full call stack?
考虑这个简单的例子:
public class Overflow {
public Overflow() {
new Overflow();
}
public static void a() {
new Overflow();
}
public static void main(String[] argv) {
a();
}
}
现在报告的错误是:
Exception in thread "main" java.lang.StackOverflowError
at Overflow.<init>(Overflow.java:11)
[last line repeated many times]
但我在堆栈跟踪中看不到 main
和 a
方法 . 我的猜测是因为溢出,堆栈中的最新条目取代了最旧的条目(?) .
现在,如何在输出中获取 a
和 main
堆栈条目?
背景是我得到了一个StackOverflowError(但是当增加堆栈大小时会发生这种情况)并且很难发现代码中的问题 . 我只从 java.util.regex.Pattern
获得多行,但不知道代码所谓的信息 . 应用程序太复杂,无法在每次调用 Pattern
时设置断点 .
5 回答
JVM具有1024个条目的人为限制,您可以在异常或错误的堆栈跟踪中拥有这些条目,可能在发生时节省内存(因为VM必须分配内存来存储堆栈跟踪) .
幸运的是,有一个标志允许增加此限制 . 只需使用以下参数运行程序:
这将打印多达100万个堆栈跟踪条目,这应该绰绰有余 . 也可以在
-1
设置此值以将条目数设置为无限制 .This list of non-standard JVM options提供更多详细信息:
使用此标志运行问题的示例将得到以下结果:
这样,即使实际堆栈跟踪长度超过1024行,您也可以找到引发错误的代码的原始调用者 .
如果您不能使用该选项,还有另一种方法,如果您处于这样的递归函数中,并且您可以修改它 . 如果添加以下try-catch:
从本质上讲,这将创建并抛出一个新的
StackOverflowError
,丢弃最后一个条目,因为每个条目将比前一个条目向上发送一级(这可能需要几秒钟,因为必须创建所有这些错误) . 当堆栈跟踪将减少到1023个元素时,它只是被重新抛出 .最终,这将在堆栈跟踪的底部打印1023行,这不是完整的堆栈跟踪,但可能是它最有用的部分 .
据我所知,不可能获得完整的堆栈跟踪(但是,我真的不知道为什么) .
但是,您可以采取的措施来跟踪问题,就是在受影响的代码中手动检查堆栈深度,如下所示:
需要通过实验找到
SOME_VALUE
(足够高以至于不能在"good"情况下触发并且足够低以至于无法到达) . 当然这会降低您的代码速度,并且只应该用于调试问题 .更新:我似乎错过了
Pattern
中出现的问题,这使问题变得复杂 . 但是,您可以在堆栈跟踪中的一个Pattern
方法上使用条件方法断点,条件如下(实际值可能需要调整):这样,当您点击断点时,您可以在堆栈底部找到自己的代码 .
如果您的堆栈不足,请考虑创建一个具有足够堆栈的专用线程,尤其是用于运行请求 . 示例代码如下 .
我会尝试插入一些东西来装饰类似于ExceptionUtils的堆栈跟踪输出,以便对同一个Class或Package重复调用 .
我会在重现问题时触发手动线程转储 . 很可能只有一段时间后才会抛出stackoverflow . 因此,我们可以快速触发jvm上的Thread转储,这将通过在堆栈飞越之前打印整个有问题的线程堆栈来向我们提供有关调用者的详细信息 .