如何扩大Java堆栈跟踪的大小以查看堆栈底部?(触发堆栈溢出)

17
在Java中,有没有办法查看完整的、未经截断的堆栈跟踪(例如通过增加记录的帧数),或者以其他方式进入堆栈跟踪的底部?通常情况下,堆栈跟踪从顶部截断 1024 帧,但对于堆栈溢出问题而言,这几乎毫无意义,因为您确实需要看到谁调用了触发递归的函数,位于底部附近。更好的情况是在堆栈的中间截断,但显然Sun的JVM不够智能。
也许甚至有一些特殊的Sun特定标志?我尝试将堆栈大小减小到最小允许值(-Xss1000),但那仍然超过 1024 帧。
在我的情况下,我正在尝试调试在Hadoop mapper中发生的堆栈溢出,但仅当运行非常大的输入时才会出现。我认为问题是因为在一个非常非常大的链接列表上执行了一个递归操作(Scala的foldRight),我需要将其重写为非递归...但我需要知道谁调用了foldRight。这是一个基本例程,在许多地方直接和间接调用,并且有很多代码可以使用,因此这是高度不明显的。

1
你是否考虑将对foldright的调用重写为尾递归函数?这可能不太容易,但如果你能做到的话,它可能会解决你的问题。 - Squidly
这里是一个JDK的错误报告,描述了相同的问题。在评论中,描述了一个解决方法,与Odd的答案相同。 - DBear
4个回答

27

尝试使用-XX:MaxJavaStackTraceDepth JVM选项。

以下是来自Stas的博客的描述。

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)。


2
你可以自己遍历堆栈跟踪。
Throwable t =

for(StackTraceElement ste: t.getStackTrace()) {
    // is it a repeat??

}

默认的printStackTrace会打印出所有已记录的堆栈级别。您的问题是堆栈跟踪中的内容过于深入。您可以尝试减少堆栈大小。


-1
如果您可以在调用进入疑似堆栈溢出之前访问它,您可以像new Exception().getStackTrace一样生成额外的堆栈跟踪。请注意,foldRight本身不会产生无限递归。也许您只是用完了内存,请尝试增加JVM的堆栈大小。

2
Thread.currentThread().getStackTrace() 更为合适。 - Ryan Amos
如果foldRight被调用于一个无限的集合上,它可能会产生无穷递归。 - DBear

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接