【问题标题】:Will the stack eventually overflow?堆栈最终会溢出吗?
【发布时间】:2012-12-01 14:55:00
【问题描述】:

我已经为此解决方案进行了很多搜索,但完全没有运气。

这是我的程序的基础知识。我的主要功能中有一个循环。循环需要计算大量数据,当我给我的一个变量一个大于 20 的值时,它最终会堆栈溢出。

我知道,只要您在函数中“返回”,它就会释放整个堆栈。事情是这样的,我需要这个循环永远运行,直到人们关闭应用程序。

这甚至可能吗?在堆栈溢出发生之前,所有函数都需要很短的生命周期吗?如果我使用动态内存,我仍然无法摆脱它在运行时积累的其他堆栈数据。

基本上,我怎样才能永远运行一个函数而不会导致堆栈溢出?

【问题讨论】:

  • 给我们看一些代码。
  • 只有不断往里面放东西,栈才会溢出。让我们看看代码...
  • 欢迎来到stack(最终)overflow Amadeus!
  • 如果你继续递归,堆栈溢出......如果你的所有函数都停留在一个循环中,它不会向堆栈添加任何东西,所以它可以永远运行......跨度>
  • 这个怎么样 ---- while(x=1) {x=2} while(x=2){x=1},,, 代码最终会溢出我的堆栈吗?跨度>

标签: c++ memory dynamic stack-overflow


【解决方案1】:

运行函数不会填满堆栈。但是,如果您使用递归函数调用,是的,最终堆栈会溢出。回到你的问题 - 你说你正在主函数中运行一个导致堆栈溢出的循环,然后你说调用函数导致堆栈溢出。除非您在其中创建新对象,否则循环不会导致堆栈溢出!同样,在 C/C++ 中,主函数不能被称为递归。你不是很清楚的朋友。

如果您能分享一些示例代码,那就太好了。

PS:这很有趣,我们正在谈论stackoverflow上的stackoverflow:P

【讨论】:

  • 这段代码怎么样 while(x=1) {x=2} while(x=2) {x=1} 会溢出堆栈吗?
  • 不,它不会溢出堆栈。它在运行时根本不会增加堆栈。
  • 不,不会,因为您没有在该语句序列中创建任何内容。如果你把它们放在一个循环中,它所要做的就是将 CPU 推到 100%(它正在运行的一个核心)。但是内存不会溢出。顺便说一句,那里不需要while - 你可以使用if
【解决方案2】:

堆栈的大小有限。在某些 Windows 系统上,它是 1 MB。你可以programatically change the stack size,但通常这是个坏主意。

每个线程都有不同的堆栈。堆栈变量总是在作用域结束时被释放。例如

void MyFunction
{ // begin of scope 1
    std::string mouse("feep"); 
    for (int i = 0; i < 10000000; i++)
    { // begin of scope 2
        int x = 1;  // x is on the stack
        std::string cow("moo"); // cow is on stack
      // end of scope 2, cow is destroyed then the stack is freed for cow and x before the next iteration of the loop begins
    } 
    return; // end of scope 1, mouse is destroyed ant the stack is freed for mouse
}

在任何时候,上述代码在堆栈上最多只有mouseixcow。如果你使用recursion,你可能会得到一个非常深的堆栈,它会溢出。例如

void StackOverflowIncoming()
{ // begin of scope
    int aVariableOnTheStack = 0;
    StackOverflowIncoming();
    // end of scope
}

上面的函数永远打开一个新的作用域并且永远不会离开一个作用域,所以在某些时候它会溢出。

另一种溢出堆栈的方法是alloca,它直接分配堆栈(然后在分配它的范围关闭后立即释放它。只需使用alloca在堆栈上分配10 MB,如果最大堆栈大小为 1 MB。这也可以通过在堆栈上分配一个巨大的结构来实现。

void InstantStackOverflow()
{
    char buffer[1<<24];
}

有关堆栈上分配过多的更详细示例,请参阅question

溢出堆栈的最后也是最有创意的方法是破坏程序状态,使程序变得非常混乱并且无法清理堆栈。通常,您通过使用会导致未定义行为的语言特性来做到这一点,如下所示:

void TryToCorruptTheStack()
{ // begin of scope
    char buffer[1];
    for (int i = -20; i < 20; i++)
        buffer[i] = 5;
    // end of scope
}

有关堆栈损坏的更详细示例,请参阅question

【讨论】:

  • 除非你的编译器优化了尾调用。
  • 哇,这让它更清晰了!我的问题可能是我没有用循环声明我的变量吗?我在我的主要功能之前声明了它们。所以如果我在循环中声明它们,一旦结束它们就会消失?谢谢!
  • @Amadeus 到目前为止,还不清楚您是否有问题,因为您仍然拒绝显示您的代码或解释运行它时实际发生的情况。
  • @Amadeus 由于堆栈的设计方式,您不能真正“泄漏”堆栈上的内存。但是,您可以在堆栈上分配太多内存,或损坏堆栈。第一个通常通过使用 'alloca()' 完成,后者通常与写入未初始化的指针或写入数组中不存在的索引上的数组有关。
猜你喜欢
  • 1970-01-01
  • 2019-05-18
  • 1970-01-01
  • 2011-02-08
  • 2013-10-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-07
相关资源
最近更新 更多