Linux系统编程14:进程入门之Linux进程中非常重要的概念之进程地址空间-原来我们看到的地址全部是虚拟的
文章目錄
- (1)舊知回顧
- (2)程序地址空間?
- A:同一個地址有兩個數據?
- B:物理地址和虛擬地址
- C:進程地址空間及作用
- D:進程地址空間如何工作
(1)舊知回顧
學習C/C++總免不了這張圖
這張圖幫助我們解決了不少C/C++問題,但是我們對它的認識還是不夠深刻。現在我我們用一端C程序,深刻的取感受一下這個過程的內存地址的變化
(2)程序地址空間?
上面的圖在學習C/C++時我們稱之為程序的地址空間分布圖,說白了就是一段程序在其運行過程中的數據的內存分布情況,但是接下來的敘述可能和你所認為的有所出入
A:同一個地址有兩個數據?
如下C程序,有個全局變量val,初始值為0,使用fork創建一個子進程,然后讓父進程先睡眠三秒,先讓子進程運行,子進程運行時把val改為100,三秒后父子進程同時運行
#include <stdio.h> #include <stdlib.h> #include <unistd.h>int val=0; int main() {pid_t id=fork();if(id==0){val=100;while(1){printf("現在是子進程:val=%d,其地址為%p\n",val,&val);sleep(1);}}else if(id>0){sleep(3);while(1){printf("############################################\n")printf("現在是父進程:val=%d,其地址為%p\n",val,&val);sleep(1);}}else{exit(-1);}sleep(1);return 0;}效果如下,問題就在于同一個變量怎么會同時具有兩個不同的值?
B:物理地址和虛擬地址
我們能夠很明確一點:同一片空間不可同時具有兩個值,就像現實生活中,你不可能同時再學校又同時在家。那么只有一種解釋:你所看到并不是真實的,也就是說你所看到的地址并不是真實的物理地址,而是表象上的相同,他們對應的真實的物理地址肯定是不相同的,我們稱這種地址為虛擬地址
實際上:我們使用C/C++看到的地址,全部都是虛擬地址,真實的地址用戶看不到,而操作系統就負責將虛擬地址轉換為物理地址
可以這樣描述:父進程啟動(它的內存空間也是虛擬的不是真實的),然后遇見fork就創建了一個子進程,fork就把父進程的內存狀態拷貝了給自己一份,如果val的值沒有改變,那么操作系統本著不浪費一點空間原則,直接使用val這個虛擬地址所對應的物理地址就可以了。但是好景不長,子進程把val修改掉了,所以操作系統就把子進程val的虛擬地址所對應的物理地址進行了修改。從表面看起來好似地址沒有變,但是真實情況早都變化了。
C:進程地址空間及作用
1:早期直接訪問物理內存的缺陷所在
我們知道進程=進程控制塊PCB+代碼+數據,早期計算機,也就是沒有進程地址空間的時候進程一旦啟動,這些東西就會被全部裝入內存,那么此時進程訪問的就是真實的物理內存,如果畫一張圖,應該就是下面這樣
但是這樣防止有很大壞處:比如說野指針,放的這么近,一旦指針訪問的別的進程的數據,這就出了大亂子了。還有進程在運行過程中,是會產生數據的,產生的數據一旦不能放在本進程后面,就要另外找內存去存放,這樣就會導致不連續的現象,也增加了異常訪問的情況
2:進程地址空間的發明
所以計算機設計者意識到了這種模式缺陷,想到了一種方法:增加一個中間層,利用中間層映射物理內存。程序訪問內存時不直接訪問物理內存,先訪問中間層,如果中間層訪問沒有問題,那么操作系統就會將中間層映射到物理層,完成正常執行
一個進程創建之后,操作系統會為這個進程分配一個專屬于它的大小為4GB的虛擬進程地址空間(4GB是因為32位系統中,指針是4個字節),與它相對的是一片真實的物理地址空間,操作系統在映射虛擬內存時只會映射到那一片物理空間,而且需要特別注意這個虛擬空間并不是真的有4GB,它只是虛擬的 。由于每一個進程都有自己的虛擬的進程地址空間,所以它只能訪問自己的進程的數據,這樣做實現了隔離,也就是進程之間的相互獨立。并且把虛擬地址空間劃分為這樣,那樣的區,這樣的話也能解決數據的連續存放
3:頁表
不管怎樣,程序運行一定要在物理內存上,所以如何映射成為了關鍵,,這種映射稱為頁表
映射時,讓虛擬地址和物理地址一一對應,進程在虛擬地址上的地址就對應了物理內存上的某個地址。這樣的話就不存在非法訪問了,因為每個進程都有自己獨立的進程地址空間,如果非法訪問,頁表上根本就找不到這樣的地址,所以操作系統拒絕映射。“代碼,字符串是只讀的,數據是可讀可寫的”就是基于這個原因,雖然咋頁表上能找到,但是對代碼,字符串做了權限限制,一旦監測到這些數據類型要做一些寫入操作,那么同樣操作系統拒絕映射
D:進程地址空間如何工作
還是那個觀點“先描述,再組織”,也就是說我們看見的那個經典的棧,堆分布圖,其實本質也是一個結構體,這個結構體隸屬于task_struct,叫做task mm_struct(文件在mm_types.h)
這張圖可以說明task_stuct和task mm_struct的關系
申請空間的本質就是想內存索要空間,得到物理地址,然后在特定區域申請沒有使用的虛擬地址,建立映射關系,再返回虛擬地址
總結
以上是生活随笔為你收集整理的Linux系统编程14:进程入门之Linux进程中非常重要的概念之进程地址空间-原来我们看到的地址全部是虚拟的的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java中 equals() 和 ==
- 下一篇: css3++