【Linux】詳細理解進程地址空間

研究背景:kernel 2.6.32   32位

程序地址空間

先看一段代碼:

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

int g_val = 0;

int main(){
   pid_t id = fork();
   if(id < 0){
     perror("fork");
     return 0;
   }
   else if(id == 0){
      g_val = 100;
      printf("child[%d]: %d : %p \n",getpid(),g_val,&g_val);
   }
   else{
     sleep(3);
     printf("parent[%d]: %d : %p \n",getpid(),g_val,&g_val);
   }
   return 0 ;                                                                                        }

明明子進程時先於父進程運行的,並且對 g_val 的值進行了修改,爲什麼父進程運行的時候 g_val 的值反而還是 0?並且子進程和父進程中的 g_val 變量所存在的地址都一樣的?

得出結論:

變量內容不一樣,所以父子進程輸出的變量絕對不是同一個變量

地址一樣,說明該地址絕對不是物理地址

在Linux環境下,這個地址叫做 虛擬地址,我們在用 C/C++ 看到的地址,全部都是虛擬地址! 物理地址,用戶一概看不到,由 OS 統一管理;

進程地址空間

 

上面的這張圖就很好的解釋了上面的那段代碼:同一個變量,地址相同,起始就是虛擬地址相同,內容不同其實是被映射到了不同的物理地址。

操作系統通過 mm_struct 這個結構體個進程描述了一個虛擬的地址空間;

mm_struct{
    ulong size;
    ulong code_size;
    ulong code_end;
    ulong data_start;
    ulong data_end;
};

虛擬地址空間又通過 頁表 對於到相應的物理內存上,但是實際上在物理內存的管理是通過 頁段式內存的管理方式 管理的;

 

                     

虛擬地址空間 + 頁表:提高了內存的利用率、對內存訪問進行控制;

虛擬地址空間 + 頁表 優點:保持了進程的獨立性、充分利用內存、內存訪問控制

寫時拷貝技術

父進程創建子進程創建了子進程,但是並沒有直接給子進程開闢空間,拷貝數據。而是跟父進程映射到同一塊內存空間,但是 如果數據發生了變化,那麼就需要重新給子進程開闢內存,並且更新頁表信息,提高子進程的創建性能。

                      

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