Java堆栈溢出错误 - 如何在Eclipse中增加堆栈大小?

62

我在Eclipse中运行了一个用Java编写的程序。对于非常大的输入数据,该程序具有非常深的递归层次。对于较小的输入数据,程序可以正常运行,但是当给出大的输入数据时,我收到以下错误:

Exception in thread "main" java.lang.StackOverflowError

是否可以通过增加Java堆栈大小来解决这个问题?如果可以,那我该如何在Eclipse中操作?

更新:

@Jon Skeet

该代码递归地遍历语法树以构建数据结构。例如,代码将使用语法树中的节点执行某些工作,并在节点的两个子节点上调用自身,将它们的结果组合以给出整个树的结果。

递归的总深度取决于语法树的大小,但是当递归调用数量达到1000个时,代码似乎会失败(如果没有更大的堆栈)。

另外,我很确定代码不会因为bug而失败,因为它对于小输入有效。


9
这里似乎有些问题...stackoverflow(.com)并不是一个错误! :-) - user85421
@CarlosHeuberger,你很有趣,兄弟! - HendraWD
@HendraWD 9年前我还是个孩子 - 不是真的 [:-) - user85421
8个回答

83

打开应用程序的运行配置(Run/Run Configurations...),然后在“Java应用程序”中查找应用程序条目。

参数选项卡有一个文本框Vm arguments,输入-Xss1m(或更大的参数以获取最大堆栈大小)。默认值为512 kByte(SUN JDK 1.5 - 不知道是否在不同的供应商和版本之间有所不同)。


2
请注意此问题:http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6316197 - Jim Rush

38

这个问题 可能 可以通过增加栈大小来解决,但是更好的解决方法是尝试避免递归过深。递归算法总可以转化为迭代算法,这样可以使你的代码更具可扩展性,适用于更大的输入。否则你就只能猜测需要提供多少栈空间,这甚至可能无法根据输入明确确定。

你确定失败是由于输入大小而不是代码中的错误引起的吗?顺便问一下,这个递归有多深?

编辑:好的,在看到更新后,我会尝试重写它以避免使用递归。通常拥有一个“待处理事项”的Stack<T>是消除递归的良好起点。


我记不得jvms上尾递归的状态了。请tackline发表评论。 - Jon Skeet
1
JVM目前通常不会优化尾递归。我相信这是JVM推广到非Java语言的修复之一。 - Thorbjørn Ravn Andersen
我已经根据Jon Skeet的问题更新了问题。 - tree-hacker
2
基本上,堆栈空间就像堆一样是内存。为什么使用堆更好呢?这取决于您的应用程序和解决问题的方式。有些情况下,使用堆栈而不是堆进行内存管理更有效率。还有一些情况下,基于堆栈的算法更加简洁;例如解析器。 - ziggystar
@ziggystar 堆更好,因为它更大。为什么栈如此小的问题在这里得到了解答:https://dev59.com/_Gkv5IYBdhLWcg3wnB47。我同意递归通常更简洁、更清晰。但是当我们不能假设递归深度有任何限制时,像Jon Skeet建议的那样“去递归化”是更安全的选择。毕竟,在编程语言中作为数据结构的栈和作为内存部分的栈之所以被称为相同的名称,是有原因的。 - pepan

11

在VM参数中添加标记-Xss1024k

您也可以通过使用例如-Xss1m来增加堆栈大小以mb为单位。


5
我在使用XSOM库解析模式定义文件(XSD)时遇到了同样的问题。我将堆栈内存增加到208MB,然后出现了一个heap_out_of_memory_error错误,只能将其增加到320MB。
最终的设置为-Xmx320m -Xss208m,但仍无法长时间运行而失败。
我的函数递归地打印模式定义的整个树形结构,令人惊讶的是,对于一个4MB的定义文件(Aixm库),输出文件超过了820MB,其中使用了50MB的模式定义库(ISO gml)。
因此,我相信我必须避免递归,改用迭代和其他方式来表示输出,但我在将所有递归转换为迭代时遇到了一些困难。

4

当参数-Xss无法实现预期效果时,请尝试从以下位置删除临时文件:

c:\Users\{user}\AppData\Local\Temp\.

这对我很有帮助。

3
您需要在Eclipse中创建一个启动配置来调整JVM参数。
使用F11或Ctrl-F11运行程序后,在“运行” -> “运行配置...”下打开启动配置,并在“Java应用程序”下打开您的程序。选择“参数”选项卡,您会找到“VM参数”。
这里放置了-Xss1024k
如果您希望启动配置成为工作区中的文件(以便右键单击并运行它),请选择“常规”选项卡,并选中“保存为” -> “共享文件”复选框,浏览到您想要的启动文件位置。我通常将它们放在单独的文件夹中,因为我们会将它们检入CVS。

0

看看使用常数空间并以O(n)运行的Morris中序遍历(比您正常的递归遍历长3倍,但在空间上节省了大量空间)。如果节点是可修改的,则可以在回溯到其根时将子树的计算结果保存下来(通过直接写入节点)。


0

使用 JBOSS 服务器 时,双击服务器:

enter image description here

前往“打开启动配置

enter image description here

然后更改最小最大内存大小(例如1G,1m):

enter image description here


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