什么导致堆栈溢出?

时间:2008-09-19 23:06:42

标签: c memory malloc stack-overflow

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

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

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

6 个答案:

答案 0 :(得分:10)

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

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

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

<强>递归

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

int recurse(int number) {

    return (recurse(number));
}

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

大型本地变量

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

void hugeStack (void) {

    unsigned long long reallyBig[100000000][1000000000];

    ...
}

这个similar question有一个非常详细的答案。

答案 1 :(得分:3)

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

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

答案 2 :(得分:1)

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

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

有没有理由不能在此程序中使用调试器?

答案 3 :(得分:1)

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

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

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

答案 4 :(得分:1)

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

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

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

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

答案 5 :(得分:0)

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