內(nèi)存管理基礎(chǔ)

程序可執(zhí)行文件的結(jié)構(gòu)

一個程序的可執(zhí)行文件在內(nèi)存中的結(jié)果,從大的角度可以分為兩個部分:只讀部分和可讀寫部分。只讀部分包括程序代碼(.text)和程序中的常量(.rodata)??勺x寫部分(也就是變量)大致可以分成下面幾個部分:

.data: 初始化了的全局變量和靜態(tài)變量
.bss: 即 Block Started by Symbol, 未初始化的全局變量和靜態(tài)變量(這個我感覺上課真的沒講過啊我去。。。)
.heap: 堆,使用 malloc, realloc, 和 free 函數(shù)控制的變量,堆在所有的線程,共享庫,和動態(tài)加載的模塊中被共享使用
.stack: 棧,函數(shù)調(diào)用時使用棧來保存函數(shù)現(xiàn)場,自動變量(即生命周期限制在某個 scope 的變量)也存放在棧中。
下面就各個分區(qū)具體解釋一下:

data 和 bss 區(qū):

這兩個區(qū)經(jīng)常放在一起說,因為他們都是用來存儲全局變量和靜態(tài)變量的,區(qū)別在于 data 區(qū)存放的是初始化過的, bss 區(qū)存放的是沒有初始化過的,例如:

int val = 3;
char string[] = "Hello World";

這兩個變量的值會一開始被存儲在 .text 中(因為值是寫在代碼里面的),在程序啟動時會拷貝到 .data 去區(qū)中。

而不初始化的話,像下面這樣:

static int i;

這個變量就會被放在 bss 區(qū)中。

棧:

棧是用于存放本地變量,內(nèi)部臨時變量以及有關(guān)上下文的內(nèi)存區(qū)域。程序在調(diào)用函數(shù)時,操作系統(tǒng)會自動通過壓棧和彈棧完成保存函數(shù)現(xiàn)場等操作,不需要程序員手動干預(yù)。

棧是一塊連續(xù)的內(nèi)存區(qū)域,棧頂?shù)牡刂泛蜅5淖畲笕萘渴窍到y(tǒng)預(yù)先規(guī)定好的。能從棧獲得的空間較小。如果申請的空間超過棧的剩余空間時,例如遞歸深度過深,將提示stackoverflow。

棧是機器系統(tǒng)提供的數(shù)據(jù)結(jié)構(gòu),計算機會在底層對棧提供支持:分配專門的寄存器存放棧的地址,壓棧出棧都有專門的指令執(zhí)行,這就決定了棧的效率比較高。

堆是用于存放除了棧里的東西之外所有其他東西的內(nèi)存區(qū)域,當(dāng)使用malloc和free時就是在操作堆中的內(nèi)存。對于堆來說,釋放工作由程序員控制,容易產(chǎn)生memory leak。

堆是向高地址擴展的數(shù)據(jù)結(jié)構(gòu),是不連續(xù)的內(nèi)存區(qū)域。這是由于系統(tǒng)是用鏈表來存儲的空閑內(nèi)存地址的,自然是不連續(xù)的,而鏈表的遍歷方向是由低地址向高地址。堆的大小受限于計算機系統(tǒng)中有效的虛擬內(nèi)存。由此可見,堆獲得的空間比較靈活,也比較大。

對于堆來講,頻繁的new/delete勢必會造成內(nèi)存空間的不連續(xù),從而造成大量的碎片,使程序效率降低。對于棧來講,則不會存在這個問題,因為棧是先進后出的隊列,永遠都不可能有一個內(nèi)存塊從棧中間彈出。

堆都是動態(tài)分配的,沒有靜態(tài)分配的堆。棧有2種分配方式:靜態(tài)分配和動態(tài)分配。靜態(tài)分配是編譯器完成的,比如局部變量的分配。動態(tài)分配由alloca函數(shù)進行分配,但是棧的動態(tài)分配和堆是不同的,他的動態(tài)分配是由編譯器進行釋放,無需我們手工實現(xiàn)。

計算機底層并沒有對堆的支持,堆則是C/C++函數(shù)庫提供的,同時由于上面提到的碎片問題,都會導(dǎo)致堆的效率比棧要低。

參考鏈接

點擊這里

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容