【编译器】堆栈溢出(Stack Overflow)
来源:互联网 发布:淘宝网络兼职 编辑:程序博客网 时间:2024/06/06 00:49
堆栈溢出的本质是在某次函数调用中,编译器分配的空间超过了堆栈可以允许的范围。堆栈的大小和许多因素有关:编程语言、机器架构、多线程……操作系统为每个线程分配独立的线程栈,一般情况下为1M。
1. 较大的堆栈变量
局部变量一般在堆栈上创建,但是如果局部变量的size太大,比如int a[1000000],就会发生堆栈溢出。这种情况下,最好从堆上分配这些空间。
void foo(){//int x[1000000]; ==>int *x = new int[1000000];}
2. 递归(Recursion)层数太深
无论堆栈大小是1M还是多少,总是有限的。从函数调用中栈帧的变化可以看出,每次递归调用都会将一些必要的信息保存到栈帧,比如寄存器ebp、局部变量、参数、返回地址等等。这些信息再少也会占用一定空间,因此,递归层数过深最终会耗尽堆栈资源,并导致堆栈溢出。
#include <stdio.h>int Sum(int n){if (n <= 0)return 0;return n + Sum(n - 1);}void main(){Sum(1000000);}
Sum:pushl%ebpmovl%esp, %ebpsubl$24, %esp // 保证栈帧大小是16的倍数cmpl$0, 8(%ebp) // n <=> 0?jg.L2movl$0, %eaxjmp.L3.L2:movl8(%ebp), %eaxsubl$1, %eaxmovl%eax, (%esp) // 把n-1作为参数callSumaddl8(%ebp), %eax // n + (n - 1).L3:leaveret
从汇编代码可以看出,每次调用Sum函数,都会占用32Bytes大小的栈帧。因此,Sum(1000000)总共占用大约32M的内存,在Linux下抛出Segmentation Fault错误。
对于情形二,除了用非递归的方法来消除堆栈溢出的危险,还可以将递归转化成尾递归,如下:
int SumTail(int n, int s){if (n <= 0)return s;return SumTail(n - 1, n + s);}
SumTail:pushl%ebpmovl%esp, %ebpmovl8(%ebp), %edx // 参数nmovl12(%ebp), %eax // 参数stestl%edx, %edxjle.L2 // n <= 0?.L4:addl%edx, %eaxsubl$1, %edx // n - 1jne.L4 // 注意:这里用了jne,没有用call.L2:popl%ebpret可以看到,SumTail函数多了一个参数s,它的作用是在递归调用时累积之前调用的结果,并将其传入下一次递归调用中。由于SumTail处于方法的最后位置,除两个参数外,不再需要任何其他信息。因此方法之前所积累下的各种状态对于递归调用结果已经没有任何意义,完全可以把本次方法中留在堆栈中的数据清除,把空间让给最后的递归调用。这就是所谓的“尾递归”。
尾递归有几种优化方式,上述用到的是转化为循环处理,还有一种是消除堆栈法,暂时不做介绍。
References:
http://en.wikipedia.org/wiki/Stack_overflow
http://en.wikipedia.org/wiki/Tail_recursion
- 【编译器】堆栈溢出(Stack Overflow)
- 堆栈溢出(Stack Overflow)的解决方法
- 使用PerlRegex出现“Stack overflow”堆栈溢出的问题
- IE onpropertychange stack overflow(堆栈溢出) error fix
- vs 2008 之Stack overflow 堆栈溢出解决办法
- Stack overflow. 更改堆栈空间解决栈溢出问题
- VS中堆栈溢出问题:0xC00000FD:Stack overflow
- Visual Stdio VS 错误 error : 0xC00000FD: Stack overflow. 更改堆栈空间解决栈溢出问题
- 解决stack overflow栈溢出问题!
- 栈溢出问题(Stack overflow)【转载】
- 栈溢出的问题汇总 stack overflow
- VC中栈溢出/Stack overflow怎么办?
- 堆栈溢出 Maximum call stack size exceeded
- 堆栈溢出 Maximum call stack size exceeded
- 关于堆溢出(Stack overflow)问题的解决
- 栈溢出 (stack overflow)的原因及解决办法
- 栈溢出(stack overflow)的原因及解决办法
- IE内存溢出报错Stack overflow at line
- Oracle 临时表
- QModelIndex/Role/Model介紹<二>
- java 二分排序
- 如何查找自己的msn邮箱地址
- 单点登陆小例子
- 【编译器】堆栈溢出(Stack Overflow)
- Linux内核代码风格 from kernel
- TDM
- Activity launchMode
- 深刻理解Oracle数据库的启动和关闭
- 根据table的列名动态查找该table
- PO VO in hibernate
- Queue队列
- android listivew和scrollview 并存问题解决方式