当堆栈和堆相互碰撞时会发生什么
我很想知道堆栈和堆相冲突时会发生什么。 如果有人遇到这种情况,请他们解释一下情况。
提前致谢。
在现代操作系统上运行的现代语言中,当您尝试增长堆时,您将得到堆栈溢出(hurray!)或malloc()
或sbrk()
或mmap()
将失败。 但并不是所有的软件都是现代的,所以我们来看看失败模式:
-
如果堆栈增长到堆中,典型的C编译器将静静地开始覆盖堆的数据结构。 在现代操作系统上,将会有一个或多个虚拟内存保护页面 ,以防止堆栈无限增长。 只要保护页中的内存量至less与正在增长的过程激活logging的大小一样大,操作系统将保证您有一个段错误。 如果你的DOS在没有MMU的机器上运行,你可能会被洗劫一空。
-
如果堆增长到堆栈中,操作系统应该始终知道这种情况,某种系统调用将会失败。
malloc()
的实现几乎肯定会注意到失败并返回NULL
。 之后会发生什么取决于你。
我总是惊讶于编译器编写者希望操作系统放置防护页来防止堆栈溢出的意愿。 当然,这个技巧运行良好,直到你开始拥有数千个线程,每个线程都有自己的堆栈。
这将取决于平台。 在许多平台上,它实际上根本不可能发生(堆栈和堆栈分配在不同的页面中,而这个二者不会相遇。
请记住堆向上生长和向下堆积的想法只是概念上的。 在非常小的系统上(比如运行CP / M的老式8位微处理器),以及一些PIC和其他平面内存模型系统(没有MMU,也没有其他虚拟或受保护的内存支持),那么堆和堆栈可能实际上以这种方式实施。 在这种情况下,行为将是未定义的…但是,只要代码试图返回到损坏堆栈顶部的某个地址,或者跟随从堆的一部分到另一部分的间接指针,它几乎肯定会崩溃。 ..
在任何情况下,您都不会在任何现代的通用工作站或服务器上看到它。 你将达到资源限制并获得malloc失败,否则你将会进入虚拟内存,最终系统会将自己打翻成一堆“打红开关”。
在那些时候,现在是时候转向Egon Spengler博士的圣言了….
- Egon Spengler博士:有一件很重要的事,我忘记告诉你了。
- Peter Venkman博士:什么?
- Egon Spengler博士:不要让堆与堆栈碰撞。
- Peter Venkman博士:为什么?
- Egon Spengler博士:那会很糟糕。
- 彼得·文克曼博士(Dr. Peter Venkman):在这里,我对整个“好/坏”的事情有些模糊。 你是什么意思,“坏”?
- Egon Spengler博士:试着想像所有生命,你知道它瞬间停止,你身体里的每个分子都以光速爆炸。
- Ray Stantz博士:总质子反转!
- 彼得·文克曼博士:那很糟糕。 好的。 好,重要的安全提示。 谢谢,Egon。
如果幸运的话,你会得到一个内存不足的例外或栈例外。 如果你运气不好,程序将进入无效内存,并引发内存exception。 如果你非常不幸,程序继续进行,并且破坏了它不应该的东西,你永远不知道程序失败的原因。
当然最后宇宙可能会破裂。
如果发生堆栈/堆溢出,将会出现分段错误或内存分配错误。 这里是一个例子:
void recursiveFun () { static int i; // char *str= (char *)malloc (100); printf ("%d\t", i++); recursiveFun (); // free (str); }
假设,你调用上面的函数,它将用尽堆栈和程序将崩溃。 现在,删除注释行并再次调用该函数,您会发现分段错误发生在比早期版本更less的时间和更less的recursion中。 [在我的testing环境中,堆栈溢出在第一种情况下发生在5237765recursion之后,而在第二种情况下,发生在2616325recursion之后。