堆栈溢出是如何发生的,确保它不会发生的最佳方法是什么,或者防止堆栈溢出的方法,特别是在 Web 服务器上,但其他示例也很有趣?
答案
堆
在这种情况下,堆栈是程序运行时放置数据的后进先出缓冲区。
当您在代码中调用函数时,函数调用后的下一条指令将存储在堆栈以及可能被函数调用覆盖的任何存储空间中。
堆栈溢出
堆栈溢出是指您使用的堆栈内存多于程序应使用的内存。
许多程序员都会犯这样的错误:调用函数A,然后调用函数B,然后调用函数C,然后调用函数A。它可能在大多数情况下都有效,但只要一次错误的输入就会导致它永远陷入这个循环。
递归函数也是造成这种情况的一个原因,但如果您以递归方式编写(即您的函数调用自身),那么您需要意识到这一点并使用静态/全局变量来防止无限递归。
一般来说,您使用的操作系统和编程语言管理堆栈,但它不在您的控制范围内。
除了良好的编程实践、静态和动态测试之外,您在这些高级系统上无能为力。
嵌入式系统
在嵌入式世界中,特别是在高可靠性代码(汽车、飞机、太空)中,您需要进行广泛的代码审查和检查,但您还需要执行以下操作:
- 不允许递归和周期,执行政策和测试
- 保持代码和堆栈远离(代码在闪存中,堆栈在 RAM 中,两者永远不会相遇)
- 在堆栈周围放置保护带 - 用幻数填充的内存空白区域(通常是软件中断指令,但这里有很多选项),每秒数百或数千次查看保护带以确保
- 使用内存保护(即不在堆栈上执行,不在堆栈外读取或写入)
- 中断不会调用辅助函数 - 它们设置标志,复制数据,并让应用程序负责处理它(否则你的函数调用树可能会达到 8 层深度,产生一个中断,然后在函数调用树中执行另外几个函数)
高级语言和系统
但在操作系统上运行的高级语言中:
- 减少局部变量存储(局部变量存储在堆栈上 - 尽管编译器对此非常聪明,如果您的调用树很浅,有时会将大局部变量放在堆上)
- 避免或严格限制递归
- 不要将程序分解为越来越小的函数 - 即使不计算局部变量,每个函数调用也会在堆栈上消耗多达 64 个字节(32 位处理器,节省一半的 CPU 寄存器、标志等)
- 保持你的调用树浅(类似于上面的语句)
网络服务器
您是否可以控制甚至查看堆栈取决于您拥有的"沙箱"。is例如,可能会破坏 SQL 服务器上的堆栈。
-亚当