天天看點

程序位址空間(Linux虛拟記憶體)

目錄

    • 1. 回顧“程式”位址空間
    • 2. 程序位址空間
      • 2.1 虛拟位址空間
    • 3. 程序總結
    • 4. 簡單了解運作隊列,等待隊列

1. 回顧“程式”位址空間

在學習c語言的時候,我們為了更好的了解,把它叫做程式位址空間,從低位址到高位址,依次是,常量區,資料區,堆區,棧區,而且沒有共享映射區和核心空間的概念,我們那個隻能說是在語言方面的了解。是殘缺的。

當我們學習了c++和作業系統,就該對他有更深層次的了解。是以下面這張圖才是相對完整的。

是以他的名字也應該叫做程序位址空間。

程式位址空間(Linux虛拟記憶體)

我們寫一段代碼,測試一下他的位址。

1 #include<stdio.h>
  2 #include<stdlib.h>
  3 
  4 int g_val=0;
  5 int u_g_val;
  6 int main(int argc,char* argv[],char* env[])
  7 {
  8   printf("code address:%p\n",main);
  9   printf("init val address:%p\n",&g_val);
 10   printf("uninit val address:%p\n",&u_g_val);
 11   char* p=(char*)malloc(10);                                                                                                                                                           
 12   printf("heap address:%p\n",p);
 13   printf("stack address:%p\n",&p);
 14   printf("opt address:%p\n",argv[0]);
 15   printf("opt address:%p\n",argv[argc-1]);
 16 
 17   printf("env address:%p\n",env[0]);
 18   return 0 ;
 19 }

           

從低位址到高位址,所輸出的結果可以看到是位址遞增。我們可以看到

  1. 位址确實是遞增的。
  2. 堆棧中間差距很大很大,這中間就是共享區,共享區裡主要存放動态庫和共享記憶體。
  3. 代碼段并不是從0位址開始的
    程式位址空間(Linux虛拟記憶體)

2. 程序位址空間

其實就是,作業系統給程序劃分了一塊記憶體,程序在這個記憶體裡,這個記憶體就是位址空間,程序知道這個空間該怎麼用,他給空間劃分了一塊塊區域,但是程序并不是每一刻都在使用這個空間所有的區域。

2.1 虛拟位址空間

1 #include<stdio.h>
  2 #include<unistd.h>
  3 int g_val=100;
  4 int main()
  5 {
  6 pid_t id=fork();
  7 if(id==0)
  8 {
  9 //child
 10  while(1)
 11  {
 12 printf("g_val:%d,child: g_val:address:%p\n", g_val, &g_val);
 13 sleep(1);
 14  }
 15 
 16 }
 17 else if(id>0)
 18 {
 19   //father
 20   while(1)
 21   {
 22     printf("g_val:%d,father: g_val:address:%p\n ",g_val, &g_val);                                                                                                                      
 23     sleep(1);
 24   }
 25 
 26 }
 27 else{
 28   //error
 29 }
 30   return 0;
 31 }

           

意料之中的運作結果

程式位址空間(Linux虛拟記憶體)

當我們在子程序中把val的值改成50(在child中令

val=50

),輸出的結果不一樣,但是位址确實一樣的

程式位址空間(Linux虛拟記憶體)

是以他一定不是實體位址,因為假如是記憶體中的實體位址,位址相同值是一定相同的。

這裡我們就要引入一個叫做虛拟記憶體的概念。

程序隻能看到虛拟記憶體,子程序繼承父程序,當我們代碼中沒有寫更改資料的指令,虛拟記憶體是相同的且經過頁表,映射到同一塊實體記憶體

程式位址空間(Linux虛拟記憶體)

當子程序中發生更改資料,作業系統重新開辟一斷空間,但是虛拟記憶體位址仍然沒有變化,變的隻是頁表中的映射關系。

程式位址空間(Linux虛拟記憶體)

現在問自己3個問題,當你能回答着三個問題就說明對于位址空間這個概念就了解透徹了。

  1. 什麼是位址空間

    記憶體中存在多個程序,是以一定會存在多個位址空間,作業系統就要将他先描述,在組織。在pcb中是有着位址空間指針的。

    描述:位址空間也是一個資料結構。包含我們所劃分區域的起始。

struct mm_struct
           
程式位址空間(Linux虛拟記憶體)
  1. 為什麼要有位址空間。

    假如沒有位址空間,我們直接對實體記憶體進行操作會産生什麼情況呢,程序在記憶體當中的時候,pcb+代碼+資料,記憶體中是會有多個程序存在的,可以從兩個問題來看,假如幾個程序在實體記憶體中存放的很近,假如其中某個程序進行了操作産生新資料,後面放不下,他的空間就會不連續。而且還增加了指針越界的機率,野指針等,進而寫壞别的程序的資料。

    是以就出現了程序位址空間(虛拟),它是一塊線性連續的位址空間(代碼段,資料段,堆,共享區,棧參數環境變量,)作業系統會建立一個頁表來映射虛拟記憶體和實體記憶體的位址。是以我們看到的虛拟位址空間是連續的,至于實體記憶體是否連續,不用管,os會幫我們在頁表中進行映射。而且當我們非法通路别人的資料時,頁表沒有這種映射關系的話,作業系統也會檢測然後終止。那假如我們想通路全局資料,不小心對常量字元串進行了修改,頁表中雖然有這種映射關系,但是由于常量字元串是隻讀的頁表中也有對應的隻讀辨別也會失敗的。

  2. 位址空間怎麼工作

    當一個程序通路位址空間,位址空間會将虛拟位址通過頁表映射到實體位址,進而拿到資料。

    當編譯的時候位址空間中的資料和指令處于虛拟記憶體中,當程式運作起來它會被加載到實體記憶體中成為程序,同時頁表将虛拟位址映射到實體記憶體位址之上,配置設定空間。

3. 程序總結

  1. 什麼是程序

    程序是加載在記憶體的程式,由程序和常見資料結構(

    task_struct(控制塊),mm_struccct(程序位址空間)

    )代碼和資料構成。
  2. task struct内容

    辨別符:描述本程序的唯一辨別符,用來差別其他程序

    狀态:任務狀态,退出代碼,退出信号

    優先級:相比與其他程序的優先級

    程式計數器:程式中即将被執行的下一條指令的位址

    記憶體指針:包含程式代碼和程序相關資料的指針,還有其他程序共享的記憶體塊的指針

    上下文資料:程序執行時處理器的寄存器中的資料

    I/O狀态資訊:包含顯示的I/O請求,配置設定給程序的I/O裝置和被程序使用的檔案清單

    記賬資訊:可能包括處理器的時間總和,使用的時鐘數總和,時間限制,記賬号等。

    其他資訊

4. 簡單了解運作隊列,等待隊列

task_struct中包含了許多程序連結資訊。

運作隊列:

本質是把程序pcb進行排隊等待運作的過程。舉個例子,有很多程序想要占用cpu資源。作業系統維護了一個

runqueue

隊列。在這個隊列中存放的是程序的pcb。

等待隊列:

假如目前程序需要通路磁盤進行讀寫,他需要在一個等待隊列中等待,輪到他的時候被喚醒加載到cpu當中執行硬碟讀寫。也是存放的pcb。

繼續閱讀