内存 – 如何发生“堆栈溢出”,如何防止它?

如何堆栈溢出发生和什么是最好的方法来确保它不会发生,或方法,以防止一个,特别是在Web服务器,但其他的例子也将是有趣的?
堆栈

在本上下文中,堆栈是程序运行时放置数据的最后一个进出缓冲区。最后,首先(LIFO)意味着你最后一件事总是第一件事情 – 如果你在堆栈上推2个项目,’A’然后’B’,那么你第一件事关闭堆栈将是’B’,下一件事是’A’。

当你在代码中调用一个函数时,函数调用之后的下一条指令被存储在堆栈中,以及可能被函数调用覆盖的任何存储空间。您调用的函数可能会为其自己的局部变量使用更多的堆栈。当它完成时,释放它使用的局部变量堆栈空间,然后返回到上一个函数。

堆栈溢出

堆栈溢出是当你已经耗尽了比你的程序应该使用的堆栈更多的内存。在嵌入式系统中,堆栈只能有256个字节,如果每个函数占用32个字节,那么你只能有函数调用8深 – 函数1调用函数2谁调用函数3谁调用函数4 ….谁调用函数8调用函数9,但函数9覆盖堆栈外的内存。这可能会覆盖内存,代码等。

许多程序员通过调用函数A调用函数A,然后调用函数B,然后调用函数C,然后调用函数A.它可能在大多数时间工作,但只是一旦错误的输入将导致它永远进入那个圆圈直到计算机识别出堆叠被过度吹胀。

递归函数也是一个原因,但是如果你是递归地写(即,你的函数调用自己),那么你需要知道这一点,并使用静态/全局变量来防止无限递归。

通常,你使用的操作系统和编程语言管理堆栈,它不在你的手中。你应该看看你的调用图(一个树结构,显示从每个函数调用的主要内容),以查看函数调用的深度,以及检测不期望的循环和递归。如果他们彼此调用太多次,则意图循环和递归需要被人为检查到错误输出。

除了良好的编程实践,静态和动态测试,你不能在这些高级系统上做很多事情。

嵌入式系统

在嵌入式世界中,尤其是在高可靠性代码(汽车,飞机,空间)中,您可以进行广泛的代码审查和检查,但您还可以执行以下操作:

>禁止递归和循环 – 由策略和测试强制执行
>保持代码和堆栈远离(闪存中的代码,堆栈在RAM中,永远不会满足)
>在堆栈周围放置保护带 – 用一个魔法数字填充的空白区域(通常是软件中断指令,但这里有很多选项),以及每秒数百或数千次查看保护带确保他们没有被覆盖。
>使用内存保护(即,不在栈上执行,在栈外部不读或写)
>中断不会调用辅助函数 – 它们设置标志,复制数据,让应用程序处理它(否则你可能会得到8深入你的函数调用树,有一个中断,然后出去另外几个函数里面中断,引起井喷)。你有几个调用树 – 一个用于主进程,一个用于每个中断。如果你的中断可以互相打断…好吧,有龙…

高级语言和系统

但是在操作系统上运行的高级语言:

>减少局部变量存储(局部变量存储在堆栈上 – 虽然编译器对此很聪明,如果你的调用树很浅,有时候会把大的局部变量放在堆上)
>避免或严格限制递归
>不要将程序打破得越来越小,越小越好 – 即使没有计算局部变量,每个函数调用在堆栈上消耗多达64个字节(32位处理器,保存一半的CPU寄存器,标志等)
>保持你的调用树浅(类似于上面的语句)

Web服务器

这取决于“沙箱”,你有你是否可以控制或甚至看到堆栈。机会很好,你可以对待Web服务器,因为你会像任何其他高级语言和操作系统 – 它在很大程度上是在你的手,但检查您使用的语言和服务器堆栈。例如,可能会在SQL服务器上触发堆栈。

-亚当

http://stackoverflow.com/questions/26158/how-does-a-stack-overflow-occur-and-how-do-you-prevent-it

本站文章除注明转载外,均为本站原创或编译
转载请明显位置注明出处:内存 – 如何发生“堆栈溢出”,如何防止它?