1. 程式人生 > >C語言在記憶體中的分佈

C語言在記憶體中的分佈

先認識記憶體中的幾個區,下面的區都在記憶體中,意味著掉電會丟失。但是這不意味著記憶體條裡面真的是這樣,包括作業系統的分頁都只是對記憶體的一種管理方式,或者說是虛擬的邏輯管理。

棧區(stack):由編譯器自動分配釋放,存放函式的引數值、區域性變數、返回值等。其操作方式類似於資料結構中的棧。 堆區(heap):自己分配自己釋放,記憶體分配方式類似於資料結構的連結串列。 全域性區(靜態區)(static):用於全域性變數和靜態變數的儲存。分為:已初始化讀寫資料段(RW data),未初始化資料段(BSS,Block Started By Symbol)。 文字常量區,即只讀資料段(RO data):常量字串和使用const定義的變數所用。 程式程式碼區(Code或Text):存放函式體的二進位制程式碼。 堆區和棧區屬於動態區域,其他的屬於靜態區域,為什麼這麼說?來看看他們生成的過程:

初始化的時候:開闢未初始化資料段。 編譯生成二進位制程式碼,開闢程式碼段。 連結:開闢只讀資料段和已初始化讀寫資料段。 執行:根據程式碼開闢堆區和棧區。 在執行時候才開闢,不執行則不會開闢,稱為動態區域是不是很合理。 來看例子加深理解:

int a=0; //全域性初始化區 char *p1; //全域性未初始化區 const int A = 10; //只讀區 main() { Int b;棧 char s[]=”abc”; //棧 char *p2; //棧 static int c = 0; //全域性(靜態)初始化區 char *p3=”123456″; //123456\0在常量區,p3在棧上。 p1 = (char*)malloc(10); p2 = (char*)malloc(20); //分配得來得10和20位元組的區域就在堆區。 strcpy(p1,”123456″); //123456\0放在常量區,編譯器可能會將它與p3所向”123456″優化成一個地方。 }

堆和棧的區別 堆區和棧區用的最多,堆區用malloc或new申請,用delete和free釋放;棧區自動分配和釋放。這是第一點區別:申請方式。還有很多其他的區別,先看看系統是怎麼開闢堆和棧的吧:

棧:當執行緒創立的時候,系統會為其開闢一個棧區,是一塊連續的向低地址擴充套件儲存區,能分配多大取決於作業系統和硬體配置還有當時的環境。但是因為需要連續,所以不會很大。所以如果太多的遞迴呼叫(需要棧記錄返回值和返回位置)和記憶體分配(定義10億個變數),則會導致棧溢位,所以如果不確定變數大小不要用棧。 堆:作業系統有一個記錄空閒地址的連結串列,當我們申請堆區的時候,作業系統會遍歷連結串列,尋找第一個空間夠的(當然可能現在的系統更優化,比如找一個大小更接近的),然後將該節點從連結串列刪除,空間分給程式,多餘的部分再放回連結串列。(會導致碎片化)所以堆區是不連續的,向高地址擴充套件的儲存區。很大,但是要記得釋放,不然會記憶體洩露。如果是多執行緒的程式,會共享堆區,但是棧區獨立,所以並行儲存是堆控制的。 總結起來:

申請方式 大小不同 棧適合“殺雞”,堆適合“宰牛”。 一個會棧溢位,一個會記憶體洩露。 一個向低地址連續,一個向高地址不連續。