C# 为什么在不同的呼叫号码上引发堆栈溢出异常?

C# 为什么在不同的呼叫号码上引发堆栈溢出异常?,c#,recursion,stack-overflow,C#,Recursion,Stack Overflow,考虑以下代码: private static int i = 0; static void Main(string[] args) { DoSomething(); Console.ReadLine(); } public static void DoSomething() { Console.WriteLine(i); ++i; DoSomething();

考虑以下代码:

    private static int i = 0;

    static void Main(string[] args)
    {
        DoSomething();
        Console.ReadLine();
    }

    public static void DoSomething()
    {
        Console.WriteLine(i);
        ++i;
        DoSomething();
    }
每次运行它时,我都会在
I
变量的不同值上获得
StackOverflowException
。例如160231620016071


这背后的原因是什么?这是C#编译器中的错误吗?

您的堆栈大小不够大

您可以通过启动新线程并在构造函数中定义新的stacksize来增加默认stacksize:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
namespace ConsoleApplication3
{
class Program
{
    private static int i = 0;

    static void Main(string[] args)
    {
        Thread T = new Thread(DoSomething, 100000000);
        T.Start();
        Console.ReadLine();



    }

    public static void DoSomething()
    {
        Console.WriteLine(i);
        ++i;
        DoSomething();
    }

 }
}

Stackoverflow现在发生在150万个递归调用上。

无界递归的行为由实现定义。实现定义意味着它可以做任何事情。程序可以随时终止(或永不终止)、抛出未处理的异常或其他任何情况。例如,编译为MSIL并在64位操作系统上运行,该程序对我来说永远不会终止。这是因为允许抖动将递归转换为循环,而64位抖动就是这样做的。询问它为什么以特定值终止没有实际意义,因为运行时被允许做任何事情。

AFAIK,CLR不保证堆栈的最大深度。堆栈的最大深度是多少?这是我的观点-CLR不提供任何保证。那么:这是C#编译器中的一个bug吗?没有。但是16k真的非常的推动它。我有同样的例外在发布模式下执行同样的代码,数字是128800。。。这是80倍的解释。所以,运行时拥有完全的权限,可以停止并抛出异常,也可以继续重复。我不确定我是否真的将尾部调用描述为一个循环,但我想它传达了一个相同的信息,即堆栈的大小不够大,无法进行无限次的跳转(不包括尾部调用)