什么导致堆栈溢出?

您可能认为这是一个巧合,我的问题的主题类似于论坛的名称,但我实际上是通过谷歌搜索术语“堆栈溢出”。

我使用OPNET网络模拟器,我使用C进行编程。我认为我遇到了大数组大小的问题。 看来我正在达到某种内存分配限制。 它可能与OPNET,Windows,我的笔记本电脑内存或最有可能的C语言有关。 当我尝试使用具有数千个整数的元素总数的嵌套数组时,会导致该问题。 我认为我超出了整体内存分配限制,我想知道是否有办法增加这个上限。 这是确切的问题描述:

我基本上有一个路由表。 我们称之为routing_tbl [n],这意味着我支持30个节点(路由器)。 现在,对于此表中的每个节点,我保留信息。 大约有许多(数百个)可用路径,在一个名为paths [p]的数组中。 同样,对于此数组中的每个路径,我将属于它的节点列表保存在名为hops [h]的数组中。 所以,我至少使用了nph整数值的内存,但是这个表也包含其他信息。 在同一个函数中,我也使用另一个嵌套数组,它也消耗了近40,000个整数。 一旦我运行我的模拟,它就会退出抱怨堆栈溢出。 当我减少路由表的总大小时,它可以工作。 您认为导致问题的原因是什么?如何解决? 非常感谢阿里

如果您发布一些代码可能会有所帮助。 编辑问题以包括问题function和错误。

同时,这是一个非常通用的答案:

堆栈溢出的两个主要原因是1)递归函数,或2)大量局部变量的分配。

递归

如果你的函数调用自己,就像这样:

int recurse(int number) { return (recurse(number)); } 

由于局部变量和函数参数存储在堆栈中,因此它将填充堆栈并导致堆栈溢出。

大局部变量

如果您尝试分配大量的局部变量,那么您可以轻松地溢出堆栈。 像这样的函数可能会导致问题:

 void hugeStack (void) { unsigned long long reallyBig[100000000][1000000000]; ... } 

这个类似的问题有一个非常详细的答案。

不知何故,你使用了很多堆栈。 可能的原因包括您正在堆栈上创建路由表,您将它传递到堆栈上,否则您将生成大量调用(例如通过递归处理整个事件)。

在前两种情况下,您应该在堆上创建它并传递指向它的指针。 在第三种情况下,您需要以迭代forms重写算法。

当嵌入式递归调用的数量太高时,堆栈溢出可能发生在C中。 也许你自己多次调用一个函数?

此错误也可能是由于在静态声明中分配了太多内存。 您可以通过malloc()切换到动态分配来修复此类问题。

有没有理由不能在这个程序上使用调试器?

这取决于您声明变量的位置。

局部变量(即在堆栈上声明的变量受最大帧大小限制)这是您正在使用的编译器的限制(通常可以使用编译器标志进行调整)。

动态分配的对象(即堆上的对象)受可用内存量的限制。 这是操作系统的一个属性(如果你有一个智能操作系统,技术上可以通过更大的物理内存)。

许多操作系统会在您使用更多堆栈时动态扩展堆栈。 当你开始写入一个刚刚超出堆栈的内存地址时,操作系统会假设你的堆栈已经增长了一些,并为它分配了一个额外的页面(通常在x86上为4096Kib – 正好是1024个整数)。

问题是,在x86(和其他一些架构)上,堆栈向下增长但Carrays向上增长。 这意味着如果您访问大型数组的开头 ,您将访问距离堆栈边缘一页以上的内存。

如果数组的末尾开始将数组初始化为0(这是正确的,请执行for循环),错误可能会消失。 如果他们这样做,这确实是问题所在。

您可能能够找到一些OS API函数来强制堆栈分配或编译器编译指示/标志。 我不确定这可以如何移植,除了当然使用malloc()和free()!

你不太可能遇到无线编译C的堆栈溢出,除非你做一些特别恶劣的事情,比如失控的递归或宇宙内存泄漏。 但是,您的模拟器可能有一个线程包,它将强加堆栈大小限制。 当你启动一个新线程时,它将为该线程的堆栈分配一块内存。 可能,您可以在某处建立一个参数来建立默认的堆栈大小,或者可以有一种方法来动态增长堆栈。 例如,pthreads有一个函数pthread_attr_setstacksize(),您可以在启动新线程之前调用它来设置其大小。 您的模拟器可能使用也可能不使用pthread。 请参阅模拟器参考文档。