程式位址空間
我們先看一下一般的程式位址空間(假設是32位下的作業系統4G記憶體):
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICM38FdsYkRGZkRG9lcvx2bjxiNx8VZ6l2cs0TPR10dZpnT31kaNBDOsJGcohVYsR2MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL3kzNwIzMwIjMxITNwAjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
接下來我們看一段有意思的代碼:
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
int gval=100;//定義一個全局變量
int main()
{
pid_t pid=fork();//建立子程序
if(pid==0)
{
gval=10;//在子程序中對全局變量進行修改
printf("this is child:%d-gval=%d\n-%p\n",pid,gval,&gval);
}
else if(pid>0)
{
sleep(2);
printf("this is parent:%d-gval=%d\n-%p\n",pid,gval,&gval);
}
return 0;
}
大家會覺得結果 gval 會是10 ,結果如下:
可以看到子程序的确是将gval修改成了10 但是父程序依然列印出的gval 是100 ,并且大家可以發現兩個變量的位址确實相同的?
變量:像是一塊空間的别名,通過别名可以通路空間中的内容
空間:用來存儲資料的,一塊空間隻會存儲一個資料
在我們中的程式中發現一個全局變量在父子程序中的資料時不一樣的,一塊空間值能存儲一個資料,表明父子gval變量用的肯定不是同一個空間 但是經過列印發現,位址也是一樣的
提出疑問:難道同一個空間同時存儲了兩個變量gval 一個是10 另一個是100?
當然這是不可能的!那麼如何解釋這個現象呢?
這裡提出一個問題,我們列印出來的位址就是實際的實體位址嗎?并不是,是以引入虛拟位址空間的概念。
虛拟位址空間
記憶體位址:對記憶體區域的編号,用過編号就可以尋找到相應的空間
實際上我們在程序中所看到的位址都是虛拟位址,而不是實體記憶體的機關編号
我們所說的程式位址空間實際上是一個虛拟位址空間
虛拟位址空間到底是什麼?
實際上虛拟位址空間是作業系統給程序描述的一個虛假的位址空間
比如說我們使用的某盤–某盤說給每個人免費的都有1G空間甚至說有5 G 100G的空間,據調查中國有接近9億的網民,它為什麼敢說給每人那麼多空間呢
其實通過虛拟位址空間,可以給程序造成一個假象:我有連續的,完整的記憶體使用
虛拟位址空間是作業系統通過一個struct mm_struct 結構描述的虛拟空間;就是虛拟的編号
比如一張桌子是1m 然後你和你的同桌進行劃分 0-80 是你的 20- 100是你同桌的 看似兩個人同同時擁有了80厘米的空間但是其實是虛拟的
為什麼要使用虛拟位址空間:例如:
作業系統中的記憶體管理方式: 分段式/分頁式 /段頁式
先配置設定虛拟位址還是配置設定實體記憶體?:
先配置設定虛拟位址,然後再将資料存儲在實體記憶體,當申請空間但不占用空間時(不進行資料存儲),隻開一個空頭支票,當要存儲資料的時候再進行實體記憶體的配置設定
分段式:将位址空間進行分段 ,代碼段/資料段/堆/棧/參數/環境變量
根據使用一個空間的性質,在不同的分段,配置設定虛拟位址,有助于編譯器的記憶體管理
虛拟位址的組成:段号+段内的偏移量
在作業系統中有一個段表,表中包含:虛拟段号,實體記憶體段起始位址
段表:
通過虛拟位址中的段号,在段表中找到相應的段表項,得到實體段起始位址,加上段内偏移最終得到實體位址
但是這樣的話還是會有很多的記憶體碎片
分頁式記憶體管理:
虛拟位址的組成:頁号+頁内偏移量
在作業系統中有一個頁表,頁表中包含:虛拟頁号,實體塊号,記憶體通路控制标志,缺頁中斷位
分頁式記憶體管理主要實作資料在實體記憶體上的離散式存儲以及頁面的通路控制
頁内偏移占多少個位元組取決于頁面的大小 例如一個頁面時4096個位元組的話 占低12 位 因為 2^12=4096
其他的為頁号所占的位數
段頁式:在分段的基礎上,每個分段内進行分頁式管理 (現在電腦所使用的)
位址組成:段号-段内頁号-頁内偏移
通過段号在段表中找到記憶體段對應的頁表位址 ,根據位址找到頁表 ,通過段内頁号找到頁表項,得到實體起始位址(或者實體塊号)加上頁内偏移
段表中包含:段号+段内頁表起始位址 頁表包含:頁号+頁内偏移
其實了解了這些,我們可以知道,雖然列印出的位址是相同的,但是其實實際的實體位址是不同的,為子程序又重新開辟了空間,存儲了變量gval.