C#:递归方法期间的堆栈溢出异常
Posted
技术标签:
【中文标题】C#:递归方法期间的堆栈溢出异常【英文标题】:C# : Stack Overflow Exception during recursive method 【发布时间】:2020-12-17 10:03:45 【问题描述】:我有一个递归方法,只要随机生成的数字不等于 1,它就会调用自己。 我正在尝试测试不同事物的赔率,例如闪亮的口袋妖怪 (1/8192) 或 Minecraft 中的 12 眼种子 (10^12),即使我了解 Stack Overflow 发生的原因,但我不知道如何修复它。使用线程会大大降低速度(5000 次计算/秒,没有线程,大约 500 次)。
代码如下:
static void shiny()
total = 0;
counter += 1;
resetcounter += 1;
if (rdm.Next(8192) + 1 == 1)
Console.WriteLine("SHINY !! In: " + counter + " resets.");
else
if (resetcounter > 7000)
Console.WriteLine("Reset. Current: " + counter);
ThreadStart newtask = new ThreadStart(shiny);
Thread task = new Thread(newtask);
task.Start();
else
Console.WriteLine("Reset. Current: " + counter);
shiny();
我使用 resetcounter 变量来避免堆栈溢出错误,因为它发生在 7k 次“重置”左右,然后它启动一个新线程。 不过,我很想了解测试赔率如何避免堆栈溢出!
【问题讨论】:
为什么这是递归而不是带有中断条件的简单循环? 哦,我没想到,我猜我是小脑袋哈哈!循环确实有效,谢谢! 【参考方案1】:了解一些背景信息。 C# 和许多其他语言在调用方法时使用call stack,这用于局部变量、返回值和其他内容。因此,当您调用一个方法时,堆栈的大小会增加,并在方法返回时减少相同的数量。最大大小通常为 1-4Mb,并且在使用没有明确定义的最大深度的递归代码时很容易达到。
递归函数可以重写为迭代函数。有些情况需要一个显式的stack,它可以更大,但在这种情况下不需要。示例代码,减去线程,可以重写如下:
void shiny()
while (rdm.Next(8192) != 0)
counter += 1;
Console.WriteLine("SHINY !! In: " + counter + " resets.");
虽然这样的实验很有趣,但您可以明确地计算概率。假设在一轮中找到一个闪亮的机会是 8192 分之一,或 0.012%,那么在 n 轮之后发现至少一个闪亮的机会将是 1 - (8191/8192)^n。把它扔到 wolfram alpha 中,你会得到一个 probability plot。
【讨论】:
以上是关于C#:递归方法期间的堆栈溢出异常的主要内容,如果未能解决你的问题,请参考以下文章