C語言的記憶體布局

2021-07-13 17:18:19 字數 3400 閱讀 2579

乙個典型c程式的的記憶體表達包括如下部分:

1. 文字段

2. 初始化資料段

3. 未初始化資料段

4. 棧區

5. 堆區

乙個執行程序的典型的記憶體布局

1. 文字段

乙個文字段,也被稱作**段或者簡稱為文字,是乙個程式在物件檔案或者在記憶體中的其中一部分,包含可執行的指令。

在記憶體區,文字段可能放在堆區或者棧區的下面,這主要是為了防止堆或棧的溢位從而覆蓋它。

通常情況下,文字段是共享的,這樣使得為了頻繁執行的程式在記憶體中僅僅只需要乙個拷貝,例如文字編輯器,c編譯器,shell等等。另外,文字段通常是唯讀的,主要是為了防止程式被不小心地更改它的指令。

2. 初始化資料段

初始化資料段,通常也被稱為資料段。資料段是乙個程式的虛擬位址空間的一部分,它包含著被程式設計師初始化的全域性變數和靜態變數。

注意,資料區並不是唯讀的,因為它的值可以在執行時被改變。

這個段又可以進一步被分為初始化唯讀區和初始化讀寫區。

例如,在c中被定義為全域性變數的char s = "hello world"和位於main(也就是全域性的)以外的語句int debug=1,會被儲存在初始化讀寫區。乙個全域性c語句,比如const char* string = "hello world",會將字串值"hello world"儲存在初始化唯讀區,而字元指標變數則會被儲存在初始化讀寫區。

例如:static int i = 10,將會儲存在資料區,同樣,global int i = 10也會儲存在資料區。

3. 未初始化資料段

未初始化資料段,經常被稱為"bss"資料段,它以乙個古老的彙編器運算子代表著"block started by symbol"來命名。在程式開始執行之前,這個段中的資料會被核心初始化為0。

未初始化段起始於起始於資料段的結尾,並且包含所有的全域性變數和靜態變數,這些變數會被初始化為0,而且沒有在源**中有顯示地進行初始化操作。

例如乙個變數宣告為static int i;會被存放在bss段。

再比如乙個全域性變數宣告為int j;也會被存放在bss段。

4. 棧

傳統上棧區和堆區是緊鄰的,但是增長方向相反;當棧的指標遇到了堆的指標,則表明空閒的記憶體被耗盡了。(在現代大位址空間和虛擬記憶體技術下,它們可能被放在任意的位置,但是它們的增長方向仍然是典型的相反。)

棧區包含程式棧,就是lifo結構,典型地是位於記憶體的高位址部分。在標準的x86計算機架構下,它朝著位址為0的方向增長;在一些其它的架構下,它朝著相反的方向增長。乙個「棧指標」暫存器跟蹤棧的頂點,每次乙個新的值壓到棧中,該指標跟著進行調整。為了乙個函式的呼叫而壓進的值的集合稱為「棧幀」;乙個棧幀包含最小的返回位址。

自動變數和每一次函式被呼叫所儲存的資訊都存放在棧中。每一次函式被呼叫,返回的位址以及關於呼叫者環境的特定資訊,比如一些機器暫存器,都會儲存在棧中。新的呼叫的函式然後為其自動和臨時變數在棧上分配空間。這就是在c語言中遞迴函式工作的原理。每一次遞迴函式呼叫它自己時 ,就會用到乙個新的棧幀,所以乙個變數的集合不會影響到該函式的其它例項的變數。

5. 堆

堆通常是動態記憶體申請所在的段。

堆區起始於bss段的終點,並向著位址增大的方向增長。堆區通過malloc,realloc和free函式進行管理,可能會用到brk和sbrk系統呼叫來調整它的大小(注意brk/sbrk的使用和乙個單一的「堆區」並不需要滿足malloc/realloc/free的要求;它也可以通過使用mmap來實現逆轉潛在的虛擬記憶體的非連續區域到程序的虛擬位址空間)。在乙個程序中所有的共享庫和動態載入模組共享堆區。

例項:size(1)命令報告出文字段,資料段,和bss段的大小(以bytes為單位)(為了更深入的了解,請參考size(1)的man page)

1. 檢查如下簡單地c程式

#include int main(void)

fengxi@ubuntu:~/c/memeory$ size memory-layout

text data bss dec hexfilename

1033 276 4 1313 521memory-layout

2. 讓我們在程式中增加乙個全域性變數,然後再來檢查bss的大小

#include int global; /* uninitialized variable stored in bss*/

int main(void)

fengxi@ubuntu:~/c/memeory$ size memory-layout

text data bss dec hexfilename

1033 276 8 1317 525memory-layout

3. 讓我們增加乙個靜態變數,也是儲存在bss中。

#include int global; /* uninitialized variable stored in bss */

int main(void)

fengxi@ubuntu:~/c/memeory$ size memory-layout

text data bss dec hexfilename

1033 276 12 1321 529 memory-layout

4. 讓我們初始化靜態變數,它將會儲存在資料段中。

#include int global; /* uninitialized variable stored in bss */

int main(void)

fengxi@ubuntu:~/c/memeory$ size memory-layout

text data bss dec hexfilename

1033 280 8 1321 529memory-layout

5. 讓我們初始化全域性變數,也將被儲存在資料段中。

#include int global = 10; /* uninitialized variable stored in bss */

int main(void)

fengxi@ubuntu:~/c/memeory$ size memory-layout

text data bss dec hexfilename

1033 284 4 1321 529memory-layout

此文翻譯自

這裡

C語言記憶體布局

重點關注以下內容 c語言程式在記憶體中各個段的組成 c語言程式連線過程中的特性和常見錯誤 c語言程式的執行方式 一 c語言程式的儲存區域 由c語言 文字檔案 形成可執行程式 二進位制檔案 需要經過編譯 彙編 連線三個階段。編譯過程把c語言文字檔案生成匯程式設計序,彙編過程把匯程式設計序形成二進位制機...

c語言記憶體布局

在linux系統下乙個c語言程序的記憶體布局 寫c程式時,我們經常會列印乙個指標位址,說這個指標指向某某記憶體位址.可這些位址是真實物理記憶體位址嗎?不是 這些只是虛擬記憶體位址.當乙個c程式調入記憶體開始執行後,在記憶體中就會產生乙個程序.而在多工作業系統中每個程序都擁有一片屬於自己的記憶體空間 ...

c語言記憶體布局

在linux系統下乙個c語言程序的記憶體布局 寫c程式時,我們經常會列印乙個指標位址,說這個指標指向某某記憶體位址.可這些位址是真實物理記憶體位址嗎?不是 這些只是虛擬記憶體位址.當乙個c程式調入記憶體開始執行後,在記憶體中就會產生乙個程序.而在多工作業系統中每個程序都擁有一片屬於自己的記憶體空間 ...