8

不使用递归如何抛出堆栈溢出异常?

4

10 回答 10

20

由于没有其他人提到它:

throw new System.StackOverflowException();

您可以在测试或进行故障注入时这样做。

于 2009-10-17T23:45:10.757 回答
17

将 ENORMOUS 数组声明为局部变量。

于 2009-10-17T23:28:43.850 回答
12

如果你调用了足够多的方法,堆栈溢出随时可能发生。虽然,如果您在不使用递归的情况下遇到堆栈溢出错误,您可能需要重新考虑您是如何做事的。递归非常简单,因为在无限循环中,你调用了大量的方法。

于 2009-10-17T23:29:06.423 回答
7

以下适用于 Windows,但大多数操作系统以类似的方式实现这一点。

简短的回答是:如果你触摸最后一个保护页,它会抛出。

当您的应用程序触及堆栈的底部页面时引发类型 EXCEPTION_STACK_OVERFLOW (C00000FD) 的异常,该页面标记为PAGE_GUARD保护标志,并且没有空间增长堆栈(再提交一页),请参阅如何捕获堆栈Visual C++ 应用程序中的溢出
发生这种情况的典型情况是由于堆栈上的许多函数帧(即失控递归)导致堆栈增长,这是由于帧较少但帧大小非常大(具有非常大的局部作用域的函数) object) 或通过从堆栈中显式分配_alloca.
导致异常的另一种方法是简单地故意触摸保护页面,例如。通过取消引用指向该页面的指针。这可能是由于变量初始化错误而发生的。

如果输入导致非常深的嵌套级别,则堆栈溢出可能发生在有效的执行路径上。例如,当您在 SQL Server 的 IN 或 NOT IN 子句中运行包含大量参数的查询时,会发生堆栈溢出。

于 2009-10-18T00:04:06.483 回答
2

每个尚未返回的方法调用都会消耗一些堆栈空间。(具有更多局部变量的方法会占用更多空间。)非常深的调用堆栈会导致堆栈溢出。

请注意,在内存有限的系统(移动设备等)上,您没有太多堆栈空间,并且会很快用完。

于 2009-10-17T23:32:49.490 回答
2

简短的回答:如果您有一个调用内部对象的对象,则将堆栈跟踪增加 1。因此,如果您有 1000 个相互嵌套的对象,每个对象都调用其内部对象,最终您将获得堆栈溢出。

下面是如何使用嵌套迭代器生成素数的演示:

using System;
using System.Collections.Generic;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Program p = new Program();

            IEnumerator<int> primes = p.AllPrimes().GetEnumerator();
            int numberOfPrimes = 1000;
            for (int i = 0; i <= numberOfPrimes; i++)
            {
                primes.MoveNext();
                if (i % 1000 == 0)
                {
                    Console.WriteLine(primes.Current);
                }
            }
            Console.ReadKey(true);
        }

        IEnumerable<int> FilterDivisors(IEnumerator<int> seq, int num)
        {
            while (true)
            {
                int current = seq.Current;
                if (current % num != 0)
                {
                    yield return current;
                }
                seq.MoveNext();
            }
        }

        IEnumerable<int> AllIntegers()
        {
            int i = 2;
            while (true)
            {
                yield return i++;
            }
        }

        IEnumerable<int> AllPrimes()
        {
            IEnumerator<int> nums = AllIntegers().GetEnumerator();
            while (true)
            {
                nums.MoveNext();
                int prime = nums.Current;
                yield return prime;

                // nested iterator makes a big boom     
                nums = FilterDivisors(nums, prime).GetEnumerator();
            }
        }
    }
}

没有递归,但程序将在大约 150,000 个素数后抛出堆栈溢出异常。

于 2009-10-17T23:53:00.027 回答
1

如果您正在谈论具有合理标准库的 C++,我认为这会起作用:

while (true) {
    alloca(1024 * 1024); // arbitrary - 1M per iteration.
}

有关alloca的详细信息。

于 2009-10-17T23:49:49.877 回答
0
int main()
{
  //something on the stack
  int foo = 0;
  for (
    //pointer to an address on the stack
    int* p = &foo;
    //forever
    ;
    //ever lower on the stack (assuming that the stack grows downwards)
    --p)
  {
    //write to the stack
    *p = 42;
  }
}
于 2009-10-18T00:29:16.193 回答
0

您也可以在堆栈中分配几个字节。

static void Main(string[] args)
{
    Span<byte> b = stackalloc byte[1024 * 1024 * 1024]; // Process is terminating due to StackOverflowException.
}
于 2019-10-23T10:55:24.207 回答
-1

制作 StackOverflowException 的最简单方法如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            SomeClass instance = new SomeClass();
            string name = instance.Name;
        }
    }

    public class SomeClass
    {
        public string Name
        {
            get
            {
                return Name;
            }
        }
    }
}
于 2009-10-18T00:11:12.767 回答