--- tags: C語言 --- # **C 語言程式記憶體配置概念** [**原文**](https://blog.gtwang.org/programming/memory-layout-of-c-program/) ![](https://i.imgur.com/UxHvY8u.png) \begin{gather*}C 語言程式記憶體配置\end{gather*} [(LibreOffice 原始檔)](https://blog.gtwang.org/wp-content/uploads/2017/03/memory-layout-of-c-program-diagram-20170301.odg) ## text:程式碼 文字區段(text segment)也稱為程式碼區段(code segment),這裡存放的是可執行的 CPU 指令(instructions)。 這個區段通常位於 heap 或 stack 之後,避免因 heap 或 stack 溢位而覆寫 CPU 指令。 通常文字區段的資料是可以共用的,當多個同樣的程式在執行時,在記憶體中只需要存有一份就夠了,而這個文字區段通常都是唯讀的,避免程式本身誤改了自己的 CPU 指令。 ## data:初始化靜態變數 初始化資料區段(initialized data segment)儲存的是一些已經初始化的靜態變數,例如有經過初始化的 C 語言的全域變數(global variables)以及靜態變數(static variables)都是儲存於此處。 這個區段的變數又可分為唯讀區域(read-only area)以及可讀寫區域(read-write area),可讀寫區域用於存放一般變數,其資料會隨著程式的執行而改變,而唯讀區域則是存放固定的常數。 ## bss:未初始化靜態變數 未初始化資料區段(uninitialized data segment)又稱為 bss 區段(這個名稱的起源來自於古老的組譯器,代表 block started by symbol)是儲存尚未被初始化的靜態變數,而這些變數在程式執行之前會被系統初始化為 0 或是 null。 ## stack(棧):區域變數 堆疊區段(stack segment)用於儲存函數的區域變數、Value Types (Primitives),以及各種函數呼叫時需要儲存的資訊(例如函數返回的記憶體位址還有呼叫者函數的狀態等),每一次的函數呼叫就會在堆疊區段建立一個 stack frame,儲存該次呼叫的所有變數與狀態,這樣一來同一個函數重複被呼叫時就會有不同的 stack frame,不會互相干擾,遞迴函數就是透過這樣的機制來執行的。 run-time 的 stack frame 包含了: * Parameters:函數的參數 * Return address:回傳位址,當function執行完,從哪行code繼續執行 * Local variables:區域變數 Stack frame 存活時間是規律可預測的,只存在於 function 的執行期間,一旦 function 執行完畢,系統會自動回收空間,不需要擔心 Memory Leak 在這裡發生。 ## heap (堆):動態配置變數 heap 區段的記憶體空間用於儲存動態配置的變數,例如 C 語言的 malloc 以及 C++ 的 new 所建立的變數都是儲存於此。 堆疊區段一般的狀況會從高記憶體位址往低記憶體位址成長,而 heap 剛好從對面以相反的方向成長。 其存活時間不規律不可預測的,即使已經執行完動態配置的 function ,物件仍可能存在 Heap 中,如malloc後面搭配free來釋放記憶體空間。 ## system:命令列參數與環境變數 system 區段用於儲存一些命令列參數與環境變數,這部分會跟系統有關。 範例 ```c #include <stdio.h> #include <stdlib.h> const int global_x = 1; // 儲存於 data 區段(唯讀區域) int global_y = 1; // 儲存於 data 區段(可讀寫區域) int global_z; // 儲存於 bss 區段 int main() { const static int x = 1; // 儲存於 data 區段(唯讀區域) static int y = 1; // 儲存於 data 區段(可讀寫區域) static int z; // 儲存於 bss 區段 int w = 1; // 儲存於 stack 區段 // 儲存於 heap 區段 char *buf = (char*) malloc(sizeof(char) * 100); // ... free(buf); return 0; } ``` ```cmd objdump -h "file" objdump -s "file" size "file" ``` 幾乎每個 C program 都會用到 printf , Linker 在執行時,都需要將 printf 的 object file 複製到最終的 executable object file 中。 在程式執行時,這些常用函數又會被複製到執行中的 process 的 text 中。 在一個執行數百個程式的系統中,將對記憶體資源造成極大的浪費。