2013-04-25 85 views
2

我正在为学生编写一个教育程序,他们可以在解决旅行推销员问题(时间消耗,状态的视觉表示等)时看到不同的算法是如何工作的。问题是,我不仅要展示出好的算法,还必须展示不好的算法。例如,我实现了TSP的广度优先搜索算法(可怕的选择)。StackOverFlow错误发生时的识别点

程序本身是用Java编写的。我有一个解决问题算法的单独线程,所有算法都实现了一个特定的接口,这允许我在每次迭代之后进行干涉。

所有运行在具有N个节点(n =城市数量)的树状结构上的盲搜索算法,每个节点都是一个由N个元素构成的数组,该实现在生成约50k个节点后产生一个StackOverFlow异常。我不想限制用户界面,以便可以使用有限数量的城市 - 模拟退火与数千个城市一起工作。

这里是一个问题: 有一些可靠的函数,我可以在某些指定的逻辑语句中使用,以便我可以确定系统即将崩溃时的点吗? 东西是式:如果(System.memoryLeft()< = 100/字节 /){//停止工作,并采取行动

预先感谢。

回答

-1

您可以使用public static int callbackCount跟踪堆栈中有多少个方法调用。每次输入搜索功能时,增加此计数器。每次你离开时,减少它。这显然也使用

Thread.currentThread.getStackTrace().length; 

我不太清楚有多少电话被允许在栈中,但如果你要打印出这个值,它不应该是很难找到了工作要做。

这样,您可以检查在遇到StackOverflowError之前可以进行多少次函数调用。

+0

如果我理解正确,当有太多函数调用时会发生stackoverflow? – 2013-04-25 08:08:40

+0

当必要的函数调用太多时不适用。相反,当有太多待处理的函数回调 - 当你调用一个函数时,程序必须返回到它离开的地方。它把这个位置放在堆栈上。 – Zyerah 2013-04-25 08:09:49

+0

@Telthien先生请看看这个查询http://stackoverflow.com/questions/16055441/computing-method-call-stack-size – 2013-04-25 08:16:43

1

链接到我的答案。 Simplest ways to cause stack overflow in C#, C++ and Java

这个解释是StackOverflowException对java,C,C++语言的基本原因。

由于递归方法调用,Stackoverflow异常在任何语言中都是通用引发的。

假设你有一个方法正在调用自己或任何其他方法的无限递归循环,那么它会导致Stacoverflowexception。背后的原因是方法调用堆栈得到提交,并且它不会适应ant其他方法调用。

方法调用堆栈看起来像这张图片。

enter image description here

说明 - 假设主要方法有五种报表和第三种方法具有了methodA,然后主要方法的执行被暂停在声明3和MethosA将被加载到调用堆栈的调用。然后方法A调用methodB。所以methodB也被加载到堆栈中。

所以通过这种方式,无限递归调用使得调用堆栈得到填充。所以它不能提供更多的方法。所以它抛出StackOverflowException。

而如何遇到它看到这个链接

Computing method call stack size for checking StackOverflowException

我也在找我这个查询的解决方案。

+0

该多好啊不错..我认为StackOverflow的关联直接用来存储对象的内存调用。有趣的是,我没有任何递归函数在我的应用程序...不是我的知识。也许有一些间接递归我没有意识到,谢谢:) – 2013-04-25 08:12:17

+0

@Erich Jagomagis。主要的基本原因stackoverflow异常只是递归。一次又一次地呼唤同一件事。总是乐于提供帮助。 – 2013-04-25 08:14:39

2

最简单的方法来检测它会抛出一个错误是等到它抛出和错误并捕获它。

try { 
    action(); 
} catch(StackOverflowError ste) { 
    // you can't call anything here safely, but you can return or unwind the stack. 
} 

注意:最大堆栈大小因机器而异,并基于命令行设置。它不基于多个呼叫。

如果你真的关心这个问题,我建议改变代码,它不使用递归,你完全避免这个问题。


的问题是最大的堆栈深度显示/记录是1024。如果你有一个较长的堆栈,你不会看到什么原因造成的最初。你可以做的是减少-Xss128k(或更少,如果你的JVM允许的话)的最大堆栈大小,以便你的堆栈跟踪总是足够短以便捕获。

public static void main(String... ignored) { 
    callMe(1); 
} 

private static void callMe(int i) { 
    callMe(i); 
} 

时用较小的堆栈大小

at Main.callMe(Main.java:42) 
at Main.callMe(Main.java:42) 
at Main.callMe(Main.java:42) 

many deleted 

at Main.callMe(Main.java:42) 
at Main.callMe(Main.java:42) 
at Main.callMe(Main.java:42) 
at Main.main(Main.java:38) 
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) 
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
at java.lang.reflect.Method.invoke(Method.java:601) 
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120) 
+0

他们问如何检查程序即将崩溃,而不是如何显示完整的堆栈跟踪。 – Zyerah 2013-04-25 08:12:24

+0

@Peter Lawrey先生请看一次这个查询http://stackoverflow.com/questions/16055441/computing-method-call-stack-size – 2013-04-25 08:16:14

+1

试图检测到你即将用尽就像试图检测你是堆栈即将耗尽内存通常会导致疯狂。这样做有几个问题a)难以准确地确定b)用于检测它的代码可能会导致一个问题,当它不会以其他方式发生时c)它不太可能对这些信息做任何有用的事情。首先避免过度的递归或内存消耗通常会更好。 – 2013-04-25 10:15:17