C程序中的內存分佈

一個典型的C程序存儲分區包含如下幾類:架構

  1. Text段
  2. 已初始化數據段
  3. 未初始化數據段

 


          進程運行時的典型內存佈局編輯器

 

1. Text段函數

Text段一般也稱爲代碼段,由可執行指令構成,是程序在目標文件或內存中的一部分,Text段一般放在棧或堆的下面,以防止堆棧溢出篡改其數據。佈局

一般狀況下,Text段是可共享的,對於須要頻繁調用的程序,其在內存中只須要一份拷貝便可,如文本編輯器、C編譯器、Shell等,所以text段一般設爲只讀以防止程序的突發性的修改。翻譯

 

2. 已初始化數據段debug

已初始化數據段,一般簡單稱做數據段,數據段佔據程序虛擬地址空間的一部分,內部包括全局變量、靜態變量(程序負責初始化這些變量)。需注意的是,數據段不是隻讀的,在運行時變量值是能夠變更的。指針

數據段還能夠更細的分爲初始化只讀區以及初始化可讀寫區。cdn

舉例:全局字符串 char s[] = 「hello world」,全局變量 int debug=1,靜態變量 static int i = 10 存儲在初始化可讀寫區;另外一種狀況下,const char* string = 「hello world」,字符串「hello world」存儲在初始化只讀區,string指針則存在初始化可讀寫區。blog

 

3. 未初始化數據段遞歸

未初始化數據段,一般稱做「bss」段,名字來源於古老的彙編操做符命名 「block started by symbol」,段內的數據在程序開始執行以前被內核初始化爲0值,一般開始於已初始化數據段的末尾處。段內包含初始化爲0的全局變量/靜態變量以及源碼中未顯示進行初始化的變量。

舉例:變量 static int i;  全局變量 int j;  包含在BBS段中。

 

4. 棧

棧與堆是相互毗鄰的,而且生長方向相反;當棧指針觸及到堆指針位置,意味着棧空間已經被耗盡(現在地址空間愈來愈大,及虛擬內存技術發展,棧與堆可能放置在內存的任何地方,但生長方向依然仍是相向的)。

棧區域包含一個LIFO結構的程序棧,其一般放置在內存的高地址處,在x86架構中,棧朝地址0方向生長,在其它架構也可能朝着相反的方向生長。棧指針寄存器跟蹤棧頂位置,每當有數值被壓入棧中,棧頂指針會被調整,在一個函數的調用過程當中,壓入的一系列數值被稱做「棧幀」,棧幀至少包含一個返回地址。

棧存儲着自動變量以及每次函數調用時保存的信息,每當函數被調用時,返回地址以及調用者的上下文環境例如一些機器寄存器都存儲在棧中,新的被調用函數此時會在棧上從新分配自動/臨時變量,這就是遞歸函數的工做原理。每當函數遞歸調用本身時,都會使用新的棧幀,所以當前函數實體內的棧幀內的變量不會影響另一個函數實體內的變量。

 

5. 堆

堆一般用做動態內存分配,堆空間起始於BSS段的末尾,並向高地址處生長,堆空間一般由malloc, realloc 及 free管理,這些接口可能再使用brk/sbrk系統調用來調整大小,在一個進程中,堆空間被進程內全部的共享庫及動態加載模塊所共享。

 

示例-查看可執行文件的存儲分配

注:size命令以字節爲單位統計可執行程序的text, data, 及bss段(更多詳情參考man page of size(1))

 

1. 檢查下述C程序

編譯後查看text/data/bss分佈狀況

2. 增長一個全局變量

編譯後觀察變化,bss區域增長了4字節

 

3. 再添加一個靜態變量

編譯後再看變化,bss區域增長了4字節

4. 初始化3中的靜態變量看看

此時變量存儲到了data段,data增長了4字節,bss減小了4字節

 5.繼續初始化2中的全局變量看看

此時靜態變量也存儲到了data段,data增長了4字節,bss減小了4字節

6. 添加一個全局const變量看看

 此時「haha」字符串存儲到了text段,並增長了5個字符,多出來的一個字符是\0,ptr指針存儲到了data段,增長了4個字節。

 

注:在步驟4/5中,初始化的值若爲0,編譯器仍是會將變量放入BSS區。感興趣的同窗能夠動手編譯看看。

 

文章翻譯/修改自 https://www.geeksforgeeks.org/memory-layout-of-c-program/ 

相關文章
相關標籤/搜索