文章目錄
- 🍊程式地址空間
- 🍈虛擬地址
- 🍈四個問題
- 🥝行程地址空間究竟是什么?
- 🥝為什么要存在虛擬地址空間?
- 🥝行程地址空間的分布?
- 🥝地址空間和物理記憶體之間的關系?(淺談)
- 🍈地址相同內容不同問題詳解
- 🍈行程與程式的區別?
- 🍈小技巧:塊注釋(hjkl)
🍊程式地址空間
行程地址空間圖

checkarea.c
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int glo_val=0;
int uninit_val;
int main(int argc,char* argv[],char* env[])
{
//代碼區
printf("code addr:%p\n\n",main);
//字符常量區
const char* p="hello world!";
printf("read only addr:%p\n\n",p);
//已初始化全域變數區
printf("glo_val addr:%p\n",&glo_val);
//未初始化全域變數區
printf("uninit addr:%p\n\n",&uninit_val);
//堆區
char* q=(char*)malloc(10);
printf("heap addr:%p\n\n",q);
//堆疊區
printf("stack addr:%p\n",&p);
printf("stack addr:%p\n\n",&q);
//命令列引數
printf("args addr:%p\n",argv[0]);
printf("args addr:%p\n\n",argv[argc-1]);
//環境變數
printf("env addr:%p\n\n",env[0]);
//測驗static修飾的變數在哪塊區域
static int a=0;
printf("static addr:%p\n\n",&a);
return 0;
}
運行:
將其與代碼一一對應起來:

🍈虛擬地址
#include<stdio.h>
#include<unistd.h>
int glo_val=0;
int main()
{
int ret=fork();
if(ret>0)
{
//parent
while(1)
{
sleep(1);
printf("\n i am father::glo_val:%d, &glo_val:%p\n",glo_val,&glo_val);
}
}
else
{
//child
glo_val=100;
while(1)
{
sleep(1);
printf("\n i am son:: glo_val:%d, &glo_val:%p\n",glo_val,&glo_val);
}
}
return 0;
}
運行:

觀察運行結果,為什么兩個的地址一樣,但是值卻不同???
想直接知道結果,就可以直接拉到最后了
到這里引出虛擬記憶體,顯然同一塊空間不可能有兩個值,因為我們從學C語言起(沒學系統前)取到的地址都是虛擬地址,而不是真正的物理地址,我們在語言層面拿到的都是虛擬地址,

虛擬記憶體本質上也不過是結構體(mm_struct)(
原始碼沒找到,建議Linux原始碼版本別下太高了,不好找😥),在mm_struct里規定了地址的起始,比如0x00000000到0x11111111這塊代表代碼區假如記憶體是4G,每個行程都會以為自己擁有了4G的記憶體(虛擬)
講個小故事幫助理解,一個身價十億的富豪,有十個私生子,他對每個私生子說:百年之后我把自己的所有財產都歸到你名下,私生子之間并不知道對方的存在,所以每個私生子都會以為自己擁有十億,私生子每次向自己的父親要錢父親都會給予回應
再比如你把十萬存入銀行,你以為自己有的十萬,你每次要一兩萬都能到從中取出來,你以為你擁有十萬,但是你每次取得并不是原先的十萬,
正如行程需要記憶體空間,他是覺得自己擁有全部記憶體的,
頁表就相當于一種映射關系
虛擬地址是靠作業系統提供的,虛擬記憶體與物理記憶體的轉化靠的是作業系統
行程地址空間不是記憶體,而是隨著行程一直存在(因為本身就只是C語言模擬出來的程式而已)
🍈四個問題
🥝行程地址空間究竟是什么?
-
行程地址空間本質上是行程看待記憶體的方式,在Linux原始碼里虛擬記憶體與兩個結構體的實作密切相關(其中一個就是mm_struct),地址空間也是被抽象出來的一個概念
-
區域劃分的本質(堆疊 代碼區之類的劃分)本質上是將線性的地址空間劃分為一塊一塊的,或者說給線性的地址空間加上邊界(舉個例子,假設代碼區[0x00000000,0x11111111])
-
虛擬地址的本質:在這個區域之間的地址就叫虛擬地址
-
行程地址空間在行程的生命周期內一直存在
🥝為什么要存在虛擬地址空間?
-
保護物理記憶體
沒有虛擬記憶體,直接操作物理記憶體的話,來一個惡意程式那物理記憶體容易受到打擊
-
讓記憶體管理和行程管理解耦(沒有那么緊密相關)
作業系統的主要功能:
行程管理
記憶體管理
檔案管理
設備管理
理解管理可以看看專欄前面的筆記 -
讓每個行程都可以以一樣的方式來看待代碼和資料(確定了一種方式)
🥝行程地址空間的分布?

🥝地址空間和物理記憶體之間的關系?(淺談)
虛擬地址和物理地址之間通過頁表完成映射關系
我還沒學完,所以只有一點,以后還會提到這個問題
🍈地址相同內容不同問題詳解
圖片版:
簡而言之:虛擬地址一樣,不代表在物理記憶體的地址一樣
文字版:fork()函式創建了子行程,子行程的PCB(task_struct)里的資訊大多數與父行程一樣,而glo_val=100后改變了資料,資料改變后就得拷貝一份新的資料(寫時拷貝),新的資料自然有新的地址,也即子行程通過頁表映射的地址改變了,所以訪問新的資料自然是100,而虛擬地址一樣,只是看起來一樣而已,并不能代表物理記憶體是同一塊
🍈行程與程式的區別?
-
行程是動態的,程式是靜態的
-
行程具有并發性,程式沒有
-
行程是暫時的(運行完就沒了),程式一直在
-
行程會競爭CPU資源,程式不會
-
行程與程式的組成不同,行程包括程式、資料和PCB(行程控制塊)
隨筆記錄:頁表有幫助系統進行合法性檢測的作用(比如地址越界)
語言層面是看到的都叫虛擬地址
指標越界可能影響行程獨立性
虛擬地址的線性功能利于尋址
可執行程式本身就被劃分為一個一個的區域,利于鏈接之類的操作
🍈小技巧:塊注釋(hjkl)
vim打開檔案 -> ctrl+v進入visual block模式 -> 用hjkl來操作游標(不能用上下左右方向鍵)-> 選中注釋行 -> 輸入大寫的i (I) 進入插入模式 -> 輸入//(在插入模式下) -> 按下ESC
就可以發現選中行都注釋了
演示程序:
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/413903.html
標籤:其他


