1. 程式人生 > >C語言--記憶體(說法二)

C語言--記憶體(說法二)

原始碼編譯之後,分為兩個狀態:儲存時、執行時。

儲存時

 在linux環境下,可以對編譯好的二進位制檔案執行size指令可以獲取該二進位制可執行檔案的結構情況:
# size test.out

程式碼區 全域性初始化資料區/靜態資料區 未初始化資料區 十進位制總合 十六進位制總合 檔名
text data bss dec hex filename

在這裡插入圖片描述

 未執行前,沒有調入到記憶體時,分為三個部分:程式碼區(text)、資料區(data)、未初始化資料區(bss)。

(1) 程式碼區(text)

 存放CPU可執行的機器指令,由於程式被經常使用,防止其被意外修改,程式碼區通常是隻讀的。

(2) 全域性初始化資料區/靜態資料區(data)

 存放被初始化的全域性變數、靜態變數(全域性靜態變數和區域性靜態變數)、常量資料(如字串常量)。

(3) 未初始化資料區(BSS)

 存放未初始化的全域性變數,BSS這個叫法是根據早期的彙編運算子而來的,這個彙編運算子標誌著一個塊的開始。BSS區的資料在程式開始執行之前被核心初始化為0或空指標(NULL)。

執行時

 一個正在執行的C程式,佔用的記憶體分為5個區域:程式碼區、初始化資料區/靜態資料區、未初始化資料區、堆區、棧區。
在這裡插入圖片描述


(1) 程式碼區(text)

程式碼區指令根據程式設計流程依次執行,對於順序指令,則只會執行一次,如果反覆,則需使用跳轉指令,如果進行遞迴,則需藉助棧來實現。

程式碼區包括操作碼和要操作的物件(或物件的地址引用),如果是立即數(即具體的數值,如2),將直接包含在程式碼中;如果是區域性資料,將在棧中分配空間,然後引用該資料的地址;如果是BSS區和資料區,在程式碼中同樣引用該資料的地址。

(2) 全域性初始化資料區/靜態資料區(data)

只初始化一次。上面已經說過,在程式編譯時,該區域已經被分配好了,這塊記憶體在程式的整個執行期間都存在,當程式結束時,才會被釋放。

(3)未初始化資料 區(BSS)

在執行時改變其值。

(4)棧區(stack)

存放函式的引數值和區域性變數,由編譯器自動分配釋放,其操作方式類似於資料結構的棧。其特點是不需要程式設計師去考慮記憶體管理的問題,很方便;同時棧的容量很有限,在Linux系統中,棧的容量只有8M,並且當相應的範圍結束時(如函式),區域性變數就不能再使用。

(5)堆區(heap)

有些操作物件只有在程式執行時才能確定,這樣編譯器在編譯時就無法為他們預先分配空間,只有程式執行時才分配,這就是動態記憶體分配。堆區就是用於動態記憶體分配(如malloc的動態記憶體分配),堆在記憶體中位於bss區和棧區之間,一般由程式設計師申請和釋放。

之所以分配如此多的區域,主要是因為:

一個程序在執行時,程式碼是根據流程依次執行的,程式碼只需訪問一次,當然跳轉或遞迴時程式碼會被執行多次,而資料一般都需要訪問多次,因此單獨開闢空間以便訪問和節約空間。

int a = 0;                   //全域性初始化區
char *p1;                //全域性未初始化區 

int main()
{
        int b;                // 棧
        char s[] = "abc";       //棧
        char *p2;             //棧
        char *p3 = "123456";    //123456\0在常量區,而p3在棧上

        static int c =0//全域性(靜態)初始化區 

        p1 = (char *)malloc(10);

        p2 = (char *)malloc(20); //分配得來得10和20位元組的區域就在堆區

        strcpy(p1, "123456");    //123456\0放在常量區,編譯器可能會將它與p3所指向的"123456"優化成一個地方。

        return 0;
}