为什么这种递归方法在没有变量的情况下会导致 Stack Overflow 错误?
Why does this recursive method cause a Stack Overflow error when it has no variables?
我有这样的递归方法,它不包含任何变量。为什么会抛出栈溢出异常?
class MainClass
{
static void Main() => Bark();
static void Bark() { Bark(); }
}
在上面的例子中,我没有创建任何变量。如果我创建任何变量(作为参数或在方法内部),那么这是可以理解的:在线程的堆栈中创建了许多变量,由于内存不足,我得到一个错误。
不明白,方法本身也是存储在栈中的吗?为什么我会收到错误消息?
如果您要调试这段代码并查看“调用堆栈”window,那么您会看到它试图无限次将 Bark
添加到调用堆栈,因为递归没有终点。
我相信你期待看到的是尾递归。不幸的是 C# 编译器不支持它。
堆栈帧不只是包含参数,它还包含一个return地址,让处理器知道要返回到哪里。
此外,隐藏的this
指针也是一个参数。要删除它,您需要一个 static
函数。
还有 ebp
或其他堆栈帧指针,可以在每次调用时将其压入堆栈,具体取决于确切的调用约定。
所以无论你做什么,你都会肯定会在某个时候发生堆栈溢出,除非编译器决定执行尾递归。
我有这样的递归方法,它不包含任何变量。为什么会抛出栈溢出异常?
class MainClass
{
static void Main() => Bark();
static void Bark() { Bark(); }
}
在上面的例子中,我没有创建任何变量。如果我创建任何变量(作为参数或在方法内部),那么这是可以理解的:在线程的堆栈中创建了许多变量,由于内存不足,我得到一个错误。
不明白,方法本身也是存储在栈中的吗?为什么我会收到错误消息?
如果您要调试这段代码并查看“调用堆栈”window,那么您会看到它试图无限次将 Bark
添加到调用堆栈,因为递归没有终点。
我相信你期待看到的是尾递归。不幸的是 C# 编译器不支持它。
堆栈帧不只是包含参数,它还包含一个return地址,让处理器知道要返回到哪里。
此外,隐藏的this
指针也是一个参数。要删除它,您需要一个 static
函数。
还有 ebp
或其他堆栈帧指针,可以在每次调用时将其压入堆栈,具体取决于确切的调用约定。
所以无论你做什么,你都会肯定会在某个时候发生堆栈溢出,除非编译器决定执行尾递归。