轉(zhuǎn)載绒北,詳見原文:https://www.cnblogs.com/zhangjinfu/articles/11276479.html
在《C語言程序的內(nèi)存布局(內(nèi)存模型)》中我們講到,程序的虛擬地址空間分為多個(gè)區(qū)域馆蠕,棧(Stack)是其中地址較高的一個(gè)區(qū)域期升。棧(Stack)可以存放函數(shù)參數(shù)、局部變量互躬、局部數(shù)組等作用范圍在函數(shù)內(nèi)部的數(shù)據(jù)播赁,它的用途就是完成函數(shù)的調(diào)用。
棧內(nèi)存由系統(tǒng)自動(dòng)分配和釋放:發(fā)生函數(shù)調(diào)用時(shí)就為函數(shù)運(yùn)行時(shí)用到的數(shù)據(jù)分配內(nèi)存吼渡,函數(shù)調(diào)用結(jié)束后就將之前分配的內(nèi)存全部銷毀容为。所以局部變量、參數(shù)只在當(dāng)前函數(shù)中有效寺酪,不能傳遞到函數(shù)外部坎背。
棧的概念
在計(jì)算機(jī)中,椉娜福可以理解為一個(gè)特殊的容器得滤,用戶可以將數(shù)據(jù)依次放入棧中,然后再將數(shù)據(jù)按照相反的順序從棧中取出盒犹。也就是說懂更,先放入的數(shù)據(jù)最后才能取出,而最后放入的數(shù)據(jù)必須先取出急膀。這稱為先進(jìn)后出(First In Last Out)原則沮协。
放入數(shù)據(jù)常稱為入棧或壓棧(Push)卓嫂,取出數(shù)據(jù)常稱為出椏对荩或彈出(Pop)。如下圖所示:
圖:數(shù)據(jù)的出棧和入棧
可以發(fā)現(xiàn)晨雳,棧底始終不動(dòng)行瑞,出棧入棧只是在移動(dòng)棧頂,當(dāng)棧中沒有數(shù)據(jù)時(shí)悍募,棧頂和棧底重合。
從本質(zhì)上來講洋机,棧是一段連續(xù)的內(nèi)存坠宴,需要同時(shí)記錄棧底和棧頂,才能對(duì)當(dāng)前的棧進(jìn)行定位绷旗。在現(xiàn)代計(jì)算機(jī)中喜鼓,通常使用ebp
寄存器指向棧底,而使用esp
寄存器指向棧頂衔肢。隨著數(shù)據(jù)的進(jìn)棧出棧庄岖,esp 的值會(huì)不斷變化,進(jìn)棧時(shí) esp 的值減小角骤,出棧時(shí) esp 的值增大隅忿。
ebp 和 esp 都是CPU中的寄存器:ebp 是 Extend Base Pointer 的縮寫心剥,通常用來指向棧底;esp 是 Extend Stack Pointer 的縮寫背桐,通常用來指向棧頂优烧。
如下圖所示是一個(gè)棧的實(shí)例:
棧的大小以及棧溢出
對(duì)每個(gè)程序來說,棧能使用的內(nèi)存是有限的链峭,一般是 1M~8M畦娄,這在編譯時(shí)就已經(jīng)決定了,程序運(yùn)行期間不能再改變弊仪。如果程序使用的棧內(nèi)存超出最大值熙卡,就會(huì)發(fā)生棧溢出(Stack Overflow)錯(cuò)誤。
一個(gè)程序可以包含多個(gè)線程励饵,每個(gè)線程都有自己的棧驳癌,嚴(yán)格來說,棧的最大值是針對(duì)線程來說的曲横,而不是針對(duì)程序喂柒。
棧內(nèi)存的大小和編譯器有關(guān),編譯器會(huì)為棧內(nèi)存指定一個(gè)最大值禾嫉,在 VC/VS 下灾杰,默認(rèn)是 1M,在 C-Free 下熙参,默認(rèn)是 2M艳吠,在 Linux GCC 下,默認(rèn)是 8M孽椰。
當(dāng)然昭娩,我們也可以通過參數(shù)來修改棧內(nèi)存的大小。以 VS2010 為例黍匾,在工程名處右擊栏渺,會(huì)彈出一個(gè)菜單,選擇“屬性”锐涯,會(huì)出現(xiàn)一個(gè)對(duì)話框磕诊,如下圖所示:
該圖中,我們將棧內(nèi)存設(shè)置為 4M纹腌。提示:棧也經(jīng)常被稱為堆棧霎终,而堆依然稱為堆,所以堆棧這個(gè)概念并不包含堆升薯,大家要注意區(qū)分莱褒。
當(dāng)程序使用的棧內(nèi)存大于默認(rèn)值(或者修改后的值)時(shí),就會(huì)發(fā)生棧溢出(Stack Overflow)錯(cuò)誤涎劈。使用 VS2010 并切換到 Debug 模式广凸,運(yùn)行如下的代碼:
<pre style="margin: 0px; padding: 0px; white-space: pre-wrap; overflow-wrap: break-word; font-family: "Courier New" !important; font-size: 12px !important;">1 int main(){ 2 char str[102410242] = {0}; 3 return 0; 4 }</pre>
局部字符數(shù)組 str 存儲(chǔ)在棧上阅茶,占用 2M 的內(nèi)存,超出了默認(rèn)值 1M炮障,所以會(huì)發(fā)生棧溢出錯(cuò)誤目派,如下圖所示: