函数调用为什么会 stack overflow?
date
Mar 7, 2023
slug
why-function-stack-overflow
status
Published
tags
Computer Systems: A Programmer's Perspective
summary
为什么我们需要程序栈?
type
Post
Created Time
Oct 28, 2023 01:45 PM
Updated Time
Oct 28, 2023 01:45 PM
AI summary
Status
首先,来看一段函数:
将这段函数通过
翻译成汇编语言,就是下面这段代码:
其中,第 6 行的
r := add(x, y)
和第 7 行的 print(r)
都通过 call
调用了外部的函数。函数调用的过程,实际上是在内存中开辟一段空间,用栈这个后进先出(LIFO,Last In First Out)的数据结构处理函数的调用顺序。函数准备的过程就像餐厅的服务员把盘子堆起来,调用函数的过程就像是服务员从上到下取盘子。这两个操作还有一个更加专业的叫法,压栈和出栈。
拿上面的例子来说明,函数执行的过程是 main→add→print,压栈的过程就是 print→add→main。在真实的程序里,压栈的不只有函数调用完成后的返回地址,还有函数调用过程中,需要传输的一些参数数据,这些参数数据在寄存器不够用的时候也会被压入栈中。
了解了函数的执行过程,再来讨论 stack overflow 就清晰明了了。函数的执行需要一个栈来存储数据确定函数的执行顺序,栈的大小是有限的,如果函数调用的层数太多,压栈存储的内容大于栈本身的大小,就会发生栈溢出的错误,也就是 stack overflow。可想而知,无限递归,或者无限循环,都会造成栈溢出。
顺便提一句,Go 语言的 defer 语句,就是在栈的底部,直接插入函数,用于执行 defer 函数中的内容。