linux平臺下虛擬內存管理

C程序(進程)的內存佈局

#include <stdio.h>
const int a = 10; //全局常量a

int main(void) {

  const int b = 20; //局部常量b

  int* pa = (int*)&a;

  int* pb = (int*)&b;

  *pa = 30; //可以嗎?能成功賦值嗎?

  *pb = 30; //可以嗎?能成功賦值嗎?

  return 0;

}

作爲編程新手的我,有時候寫程序難免會有種迷糊的感覺,雖然寫着代碼,但總覺得哪裏不自在不通透...像上面的代碼,我第一次看到的時候根本沒有自信回答出來,我覺着應該有不少編程新人和我一樣吧>o<

 

先從(Linux平臺下)虛擬內存管理說起,

  寫C程序時,我們經常會打印一個指針地址,說這個指針指向某某內存地址.可這些地址是真實物理內存地址嗎?不是!這些只是虛擬內存地址.

  當一個C程序調入內存開始執行後,在內存中就會產生一個進程.而在多任務操作系統中每個進程都擁有一片屬於自己的內存空間(內存沙盤),這個沙盤就是虛擬地址空間,32位下是一個4GB的大小的地址塊,這些虛擬地址通過頁表映射到物理內存.

  但系統並不會真的一下分配給每一個進程4GB的物理內存空間的映射=  =(不現實啊),4GB只能是說邏輯地址,它會隨着進程的真實需要自動擴展映射到物理內存空間,最大到4GB.

  4GB(地址0-0xFFFFFFFF)其中1GB必須保留給系統內核(這是Linux平臺下),也就是說進程自身只能擁有3GB的地址(0-0xC0000000),如圖

我自己畫的=  =:


  代碼區:程序(函數)代碼所在,由編譯而得到的二進制代碼被載入至此.代碼區是隻讀的!有執行權限.代碼區一般都從0x08048000地址開始(linux).值得注意的是,字符串字面值("Hello World")就存儲在這個區.

  數據段BSS:合稱靜態區(全局區),用來存儲靜態(全局)變量.區別是 前者(數據段)存儲的是已初始化的靜態(全局)變量,可讀寫.

後者(BSS)存儲的是未初始化的靜態(全局)變量,可讀寫.

  堆:自由存儲區.不像全局變量和局部變量的生命週期被嚴格定義,堆區的內存分配和釋放是由程序員所控制的.申請方式:C中是malloc函數,C++中是new標識符.

  棧:由系統自動分配和釋放.存儲局部(自動)變量. 一般說的堆棧,其實是指 棧!

  另外,值得注意的是,是由低地址向高地址分配空間;卻是由高地址向低地址分配空間.

下面這段代碼進一步說明C程序中各數據的內存佈局:

 

 

 

#include <stdio.h>#include <stdlib.h>

int i1 = 10; //靜態全局區(data)

int i2; //靜態全局區(bss)

static int i3 = 30; //靜態全局區(data)

const int i4 = 40;  //代碼區!!!

void fun(int i5) //棧區

{

    int i6 = 60; //棧區

    static int i7 = 70; //靜態全局區(data)

    const int i8 = 80; //棧區!!!

    char* str1 = "ABCDE"; //代碼區(字符串常量)

    char str2[] = "ABCDE"; //棧區(字符數組)

    int* pi = malloc(sizeof(int)); //堆區

    printf("&i5=%p\n", &i5);

    printf("&i6=%p\n", &i6);

    printf("&i7=%p\n", &i7);

    printf("&i8=%p\n", &i8);

    printf("str1=%p\n", str1);

    printf("str2=%p\n", str2);

    printf("pi=%p\n", pi);

    free(pi);

}

int main(void)

{

    printf("&i1=%p\n", &i1);

    printf("&i2=%p\n", &i2);

    printf("&i3=%p\n", &i3);

    printf("&i4=%p\n", &i4);

    fun(50);

    return 0;

}

 

(gcc編譯)程序輸出:

 

至此,從地址大小比較可以看出

1)靜態(static)全局變量 和 靜態(static)局部變量 都在 靜態全局區.

2)全局常量i4保存在代碼區,局部常量i8保存在棧區.

所以最上面的問題是,代碼區只讀,修改全局常量會引發運行時段錯誤,而局部常量是可以成功賦值修改的.

3)字符串字面值在代碼區(所以不可修改),但是字符指針str1在棧區;字符數組str2在棧區(所以可以修改).

 

最後要說,上述是Linux下的虛擬內存佈局順序,Windows下會有所不同.但是對於C程序中數據應該存儲在哪裏都是一致的.

 

 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章