Programming > C/C++ > Stack Overflow(堆栈溢出)
Stack Overflow(堆栈溢出)是程序调试中比较麻烦的一种错误。但总结一下,引起这种错误的原因大致就是两种:
变量申请大空间内存。
递归。
出错时,弹出下面提示框:
<img class="aligncenter size-full wp-image-440" alt="stackoverflow" src="http://7xwcvs.com1.z0.glb.clouddn.com/wp-content/uploads/2014/04/stackoverflow.png" width="517" height="253" />
其中,0x5ad95ad9的值依具体情况而不同。OxC00000FD是错误标号;
一、局部数组变量空间太大,如下:
int main(int argc, char* argv[])
{
char stack_overflow[1024*1024*5];
stack_overflow[0] = 1;
return 0;
}
解决这类问题的办法有两个,一是增大栈空间 (后文中有详细描述),二是改用动态分配 ,使用堆(heap)而不是栈(stack)。
增大栈空间:
<img class="aligncenter size-full wp-image-779" alt="increasestack" src="http://7xwcvs.com1.z0.glb.clouddn.com/wp-content/uploads/2014/04/QQ截图20140401222017.png" width="760" height="555" />
在 Visual Studio 开发环境中设置此链接器选项
打开此项目的“属性页”对话框。(快捷键Alt+F7)
单击“链接器”选项。
单击“系统”属性页。
修改两个属性中的任一个:“堆栈提交大小” “ 堆栈保留大小”
以下是MSDN中的说明:
/STACK(堆栈分配)
/STACK:<i>reserve</i>[,<i>commit</i>] //此为命令格式 用在“链接器”中的“命令行”属性页 通过输入命令调整
/STACK 选项设置堆栈的大小(以字节为单位 )。此选项仅在生成 .exe 文件时使用。
reserve (保留)值指定虚拟内存中的总的堆栈分配。对于 x86 和 x64 计算机,默认堆栈大小为 1 MB。在 Itanium 芯片组上,默认大小为 4 MB。
commit (提交)取决于操作系统所作的解释。在 Windows NT 和 Windows 2000 中,它指定一次分配的物理内存量。提交的虚拟内存导致空间被保留在页面文件中。更高的 commit 值在应用程序需要更多堆栈空间时可节省时间,但会增加内存需求并有可能延长启动时间。对于 x86 和 x64 计算机,默认提交值为 4 KB。在 Itanium 芯片组上,默认值为 16 KB。
以十进制或 C 语言表示法指定 reserve 值和 commit 值。
设置堆栈大小的另一种方法是使用模块定义 (.def) 文件中的 STACKSIZE 语句。如果两者都指定,则 STACKSIZE 重写堆栈分配 (/STACK) 选项。可以使用 EDITBIN 工具在生成 .exe 文件之后更改堆栈大小。
函数出现无限递归调用或者递归层次太深:
如:
void infinite_loop()
{
infinite_loop();
}
int main(int argc, char* argv[])
{
infinite_loop();
return 0;
}
又或者如我今天写的递归中因为考虑不周(MaxOfNode超出某个阈值以致SumOfNode永远无法达到MaxOfNode)导致出错:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
void Graph::CreateGraph()
{
tempGraphNodePosition.x = Ogre::Math::RangeRandom(-5,5);
tempGraphNodePosition.y = Ogre::Math::RangeRandom(0,10);
tempGraphNodePosition.z = Ogre::Math::RangeRandom(-5,5);
if(SumOfNode != MaxOfNode)
{
if(tempGraphNodePosition.squaredDistance(RootNode.position) <= Radius*Radius)
{
for(std::vector<GraphNode>::const_iterator itr = GraphNodeSet.begin();itr!=GraphNodeSet.end();++itr)
{
if (tempGraphNodePosition.squaredDistance(itr->position) < minDistance)
{
break;
}
else if((itr+1) == GraphNodeSet.end())
{
GraphNode tempGraphNode;
tempGraphNode.position = tempGraphNodePosition;
GraphNodeSet.push_back(tempGraphNode);
++SumOfNode;
break;
}
}
}
return CreateGraph();
}
else
return;
}
实际应用中,往往由于粗心大意或者函数间的相互调用而造成了这样的结果。解决的办法当然是找到使用递归的地方,并消除BUG。
建议看完此篇接着看《递归中隐藏的陷阱 Stack Overflow》