如何发生堆栈溢出以及确保它不会发生的最佳方法是什么,或者是哪种方法可以防止,特别是在Web服务器上,但其他示例也会很有趣?
什么可以导致java.lang.StackOverflowError?我得到的堆栈打印输出不是很深(只有5种方法).
假设我们要计算一些斐波那契数,以 997 为模。
因为n=500在 C++ 中我们可以运行
#include <iostream>
#include <array>
std::array<int, 2> fib(unsigned n) {
if (!n)
return {1, 1};
auto x = fib(n - 1);
return {(x[0] + x[1]) % 997, (x[0] + 2 * x[1]) % 997};
}
int main() {
std::cout << fib(500)[0];
}
Run Code Online (Sandbox Code Playgroud)
在 Python 中
def fib(n):
if n==1:
return (1, 2)
x=fib(n-1)
return ((x[0]+x[1]) % 997, (x[0]+2*x[1]) % 997)
if __name__=='__main__':
print(fib(500)[0])
Run Code Online (Sandbox Code Playgroud)
两者都可以毫无问题地找到答案 996。我们采用模数来保持合理的输出大小,并使用对来避免指数分支。
对于n=5000,C++ 代码输出 783,但 Python 会抱怨
RecursionError: …Run Code Online (Sandbox Code Playgroud) 我想从我的对象生成一个JSON字符串:
Gson gson = new Gson();
String json = gson.toJson(item);
Run Code Online (Sandbox Code Playgroud)
每次我尝试这样做,我都会收到此错误:
14:46:40,236 ERROR [[BomItemToJSON]] Servlet.service() for servlet BomItemToJSON threw exception
java.lang.StackOverflowError
at com.google.gson.stream.JsonWriter.string(JsonWriter.java:473)
at com.google.gson.stream.JsonWriter.writeDeferredName(JsonWriter.java:347)
at com.google.gson.stream.JsonWriter.value(JsonWriter.java:440)
at com.google.gson.internal.bind.TypeAdapters$7.write(TypeAdapters.java:235)
at com.google.gson.internal.bind.TypeAdapters$7.write(TypeAdapters.java:220)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.write(ReflectiveTypeAdapterFactory.java:89)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.write(ReflectiveTypeAdapterFactory.java:200)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.write(TypeAdapterRuntimeTypeWrapper.java:68)
at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.write(CollectionTypeAdapterFactory.java:96)
at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.write(CollectionTypeAdapterFactory.java:60)
at com.google.gson.Gson$FutureTypeAdapter.write(Gson.java:843)
Run Code Online (Sandbox Code Playgroud)
这些是我的BomItem类的属性:
private int itemId;
private Collection<BomModule> modules;
private boolean deprecated;
private String partNumber;
private String description; //LOB
private int quantity;
private String unitPriceDollar;
private String unitPriceEuro;
private String discount;
private String totalDollar;
private …Run Code Online (Sandbox Code Playgroud) 我试图弄清楚C#编译器如何处理尾调用.
(答案:他们不是.但是64位JIT会做TCE(尾部呼叫消除).限制适用.)
所以我使用递归调用编写了一个小测试,它打印了在StackOverflowException杀死进程之前调用它的次数.
class Program
{
static void Main(string[] args)
{
Rec();
}
static int sz = 0;
static Random r = new Random();
static void Rec()
{
sz++;
//uncomment for faster, more imprecise runs
//if (sz % 100 == 0)
{
//some code to keep this method from being inlined
var zz = r.Next();
Console.Write("{0} Random: {1}\r", sz, zz);
}
//uncommenting this stops TCE from happening
//else
//{
// Console.Write("{0}\r", sz); …Run Code Online (Sandbox Code Playgroud) 我刚刚在另一个问题中看到了这段奇怪的代码.我认为这会导致StackOverflowError被抛出,但它不会......
public class Node {
private Object one;
private Object two;
public static Node NIL = new Node(Node.NIL, Node.NIL);
public Node(Object one, Object two) {
this.one = one;
this.two = two;
}
}
Run Code Online (Sandbox Code Playgroud)
我认为它会爆炸,因为Node.NIL引用它自己构建.
我无法弄明白为什么它没有.
我想要阻止或处理我在写作中StackOverflowException对XslCompiledTransform.Transform方法的调用Xsl Editor.问题似乎是用户可以写一个Xsl script无限递归的东西,它只是在调用Transform方法时爆炸.(也就是说,问题不仅仅是典型的编程错误,这通常是造成这种异常的原因.)
有没有办法检测和/或限制允许的递归次数?或者任何其他想法,以防止这些代码炸毁我?
当我运行我的代码时,Node.js抛出"RangeError: Maximum call stack size exceeded"了太多递归调用引起的异常.我试图增加Node.js堆栈大小sudo node --stack-size=16000 app,但Node.js崩溃没有任何错误消息.当我在没有sudo的情况下再次运行时,Node.js打印出来'Segmentation fault: 11'.有没有可能在不删除递归调用的情况下解决这个问题?
谢谢
TL; TR
当我问这个问题时,我假设a StackOverflowException是一种阻止应用程序无限运行的机制.这不是真的.
A StackOverflowException未被检测到.
当堆栈没有分配更多内存的容量时抛出它.
[原始问题:]
这是一个普遍的问题,每个编程语言可能有不同的答案.
我不确定C#以外的语言如何处理堆栈溢出.
我今天经历了例外,并一直在思考如何StackOverflowException检测到它.我相信不可能说fe是否深度为1000次调用,然后抛出异常.因为在某些情况下,正确的逻辑可能会那么深.
在我的程序中检测无限循环的逻辑是什么?
StackOverflowExceptionclass:
https://msdn.microsoft.com/de-de/library/system.stackoverflowexception%28v=vs.110%29.aspx类文档中
提到的交叉引用StackOverflowException:https:
//msdn.microsoft.com/de -de /库/ system.reflection.emit.opcodes.localloc(v = vs.110)的.aspx
我刚刚在stack-overflow这个问题上添加了标记,并且描述说当调用堆栈消耗太多内存时它会被抛出.这是否意味着调用堆栈是我的程序的当前执行位置的某种路径,如果它不能存储更多的路径信息,那么抛出异常?
我的一位同事带着一个关于这种方法的问题来找我,导致无限循环.实际的代码有点过于介绍这里,但基本上问题归结为:
private IEnumerable<int> GoNuts(IEnumerable<int> items)
{
items = items.Select(item => items.First(i => i == item));
return items;
}
Run Code Online (Sandbox Code Playgroud)
这应该(你会认为)只是一种非常低效的方式来创建列表的副本.我叫它:
var foo = GoNuts(new[]{1,2,3,4,5,6});
Run Code Online (Sandbox Code Playgroud)
结果是无限循环.奇怪.
我认为修改参数在风格上是一件坏事,所以我稍微改了一下代码:
var foo = items.Select(item => items.First(i => i == item));
return foo;
Run Code Online (Sandbox Code Playgroud)
那很有效.也就是说,该计划已经完成; 没有例外.
更多实验表明这也有效:
items = items.Select(item => items.First(i => i == item)).ToList();
return items;
Run Code Online (Sandbox Code Playgroud)
一样简单
return items.Select(item => .....);
Run Code Online (Sandbox Code Playgroud)
好奇.
很明显,问题与重新分配参数有关,但仅限于评估延迟超出该语句.如果我添加ToList()它的工作原理.
对于出了什么问题,我有一个普遍的,模糊的想法.它看起来像是在Select迭代它自己的输出.这本身有点奇怪,因为IEnumerable如果它迭代的集合发生变化,通常会抛出.
我不明白,因为我并不熟悉这些东西如何工作的内部,这就是重新分配参数导致这个无限循环的原因.
是否有人对内部人员有更多的了解谁会愿意解释为什么无限循环发生在这里?