引言
在《Linux下C語言程序的內存布局(內存模型)》中我們講到,程序的虛擬地址空間分為多個區域,棧(Stack)是其中地址較高的一個區域。棧(Stack)可以存放函數參數、局部變量、局部數組等作用范圍在函數內部的數據,它的用途就是完成函數的調用。
棧內存由系統自動分配和釋放:發生函數調用時就為函數運行時用到的數據分配內存,函數調用結束后就將之前分配的內存全部銷毀。所以局部變量、參數只在當前函數中有效,不能傳遞到函數外部。
棧的概念
在計算機中,棧可以理解為一個特殊的容器,用戶可以將數據依次放入棧中,然后再將數據按照相反的順序從棧中取出。也就是說,先放入的數據最后才能取出,而最后放入的數據必須先取出。這稱為先進后出(First In Last Out)原則。
放入數據常稱為入棧或壓棧(Push),取出數據常稱為出棧或彈出(Pop)。如下圖所示:
可以發現,棧底始終不動,出棧入棧只是在移動棧頂,當棧中沒有數據時,棧頂和棧底重合。
從本質上來講,棧是一段連續的內存,需要同時記錄棧底和棧頂,才能對當前的棧進行定位。在現代計算機中,通常使用ebp寄存器指向棧底,而使用esp寄存器指向棧頂。隨着數據的進棧出棧,esp 的值會不斷變化,進棧時 esp 的值減小,出棧時 esp 的值增大。
ebp 和 esp 都是CPU中的寄存器:ebp 是 Extend Base Pointer 的縮寫,通常用來指向棧底;esp 是 Extend Stack Pointer 的縮寫,通常用來指向棧頂。
如下圖所示是一個棧的實例:
棧的大小以及棧溢出
對每個程序來說,棧能使用的內存是有限的,一般是 1M~8M,這在編譯時就已經決定了,程序運行期間不能再改變。如果程序使用的棧內存超出最大值,就會發生棧溢出(Stack Overflow)錯誤。
一個程序可以包含多個線程,每個線程都有自己的棧,嚴格來說,棧的最大值是針對線程來說的,而不是針對程序。
棧內存的大小和編譯器有關,編譯器會為棧內存指定一個最大值,在 VC/VS 下,默認是 1M,在 C-Free 下,默認是 2M,在 Linux GCC 下,默認是 8M。
當然,我們也可以通過參數來修改棧內存的大小。以 VS2010 為例,在工程名處右擊,會彈出一個菜單,選擇“屬性”,會出現一個對話框,如下圖所示:

該圖中,我們將棧內存設置為 4M。提示:棧也經常被稱為堆棧,而堆依然稱為堆,所以堆棧這個概念並不包含堆,大家要注意區分。
當程序使用的棧內存大於默認值(或者修改后的值)時,就會發生棧溢出(Stack Overflow)錯誤。使用 VS2010 並切換到 Debug 模式,運行如下的代碼:
int main(){
char str[1024*1024*2] = {0};
return 0;
}
局部字符數組 str 存儲在棧上,占用 2M 的內存,超出了默認值 1M,所以會發生棧溢出錯誤,如下圖所示:

ubuntu中修改棧空間大小
1、通過命令 ulimit -s 查看linux的默認棧空間大小,默認情況下 為2~10M
2、通過命令 ulimit -s 臨時改變棧空間大小:ulimit -s 51200, 即修改為50M,最大值操作系統有限制。
3、通過配置文件,修改后為默認配置,/etc/rc.local下面,ulimit -s 51200 則可設置棧空間大小
4、在/etc/security/limits.conf 中也可以改變棧空間大小。
