日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux系统编程14:进程入门之Linux进程中非常重要的概念之进程地址空间-原来我们看到的地址全部是虚拟的

發(fā)布時(shí)間:2025/3/15 linux 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux系统编程14:进程入门之Linux进程中非常重要的概念之进程地址空间-原来我们看到的地址全部是虚拟的 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

文章目錄

    • (1)舊知回顧
    • (2)程序地址空間?
      • A:同一個地址有兩個數(shù)據(jù)?
      • B:物理地址和虛擬地址
      • C:進(jìn)程地址空間及作用
      • D:進(jìn)程地址空間如何工作

(1)舊知回顧

學(xué)習(xí)C/C++總免不了這張圖

這張圖幫助我們解決了不少C/C++問題,但是我們對它的認(rèn)識還是不夠深刻。現(xiàn)在我我們用一端C程序,深刻的取感受一下這個過程的內(nèi)存地址的變化

#include <stdio.h> #include <stdlib.h>int gobal_val=100;//全局變量已經(jīng)初始化 int gobal_unval;//全局變量未初始化 int main(int argc,char* argv[],char* env[]) {printf("main函數(shù)處于代碼段,地址為:%p,十進(jìn)制為:%d\n",main,main);printf("\n");printf("全局變量gobal_val,地址為:%p,十進(jìn)制為:%d\n",&gobal_val,&gobal_val);printf("\n");printf("全局變量未初始化gobal_unval,地址為:%p,十進(jìn)制為:%d\n",&gobal_unval,&gobal_unval);printf("\n");char* mem=(char*)malloc(10);printf("mem開辟的堆空間,mem是堆的起始地址,是%p,十進(jìn)制為:%d\n",mem,mem);printf("\n"); printf("mem是指針變量,指針變量在棧上開采,其地址為%p,十進(jìn)制為:%d\n",&mem,&mem);printf("\n"); printf("命令行參數(shù)起始地址:%p,十進(jìn)制為:%d\n",argv[0],argv[0]);printf("\n");printf("命令行參數(shù)結(jié)束地址:%p,十進(jìn)制為:%d\n",argv[argc-1],argv[argc-1]);printf("\n");printf("第一個環(huán)境變量的地址:%p,十進(jìn)制為:%d\n",env[0],env[0]);printf("\n"); }

(2)程序地址空間?

上面的圖在學(xué)習(xí)C/C++時(shí)我們稱之為程序的地址空間分布圖,說白了就是一段程序在其運(yùn)行過程中的數(shù)據(jù)的內(nèi)存分布情況,但是接下來的敘述可能和你所認(rèn)為的有所出入

A:同一個地址有兩個數(shù)據(jù)?

如下C程序,有個全局變量val,初始值為0,使用fork創(chuàng)建一個子進(jìn)程,然后讓父進(jìn)程先睡眠三秒,先讓子進(jìn)程運(yùn)行,子進(jìn)程運(yùn)行時(shí)把val改為100,三秒后父子進(jìn)程同時(shí)運(yùn)行

#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("現(xiàn)在是子進(jìn)程:val=%d,其地址為%p\n",val,&val);sleep(1);}}else if(id>0){sleep(3);while(1){printf("############################################\n")printf("現(xiàn)在是父進(jìn)程:val=%d,其地址為%p\n",val,&val);sleep(1);}}else{exit(-1);}sleep(1);return 0;}

效果如下,問題就在于同一個變量怎么會同時(shí)具有兩個不同的值?

B:物理地址和虛擬地址

我們能夠很明確一點(diǎn):同一片空間不可同時(shí)具有兩個值,就像現(xiàn)實(shí)生活中,你不可能同時(shí)再學(xué)校又同時(shí)在家。那么只有一種解釋:你所看到并不是真實(shí)的,也就是說你所看到的地址并不是真實(shí)的物理地址,而是表象上的相同,他們對應(yīng)的真實(shí)的物理地址肯定是不相同的,我們稱這種地址為虛擬地址

實(shí)際上:我們使用C/C++看到的地址,全部都是虛擬地址,真實(shí)的地址用戶看不到,而操作系統(tǒng)就負(fù)責(zé)將虛擬地址轉(zhuǎn)換為物理地址

可以這樣描述:父進(jìn)程啟動(它的內(nèi)存空間也是虛擬的不是真實(shí)的),然后遇見fork就創(chuàng)建了一個子進(jìn)程,fork就把父進(jìn)程的內(nèi)存狀態(tài)拷貝了給自己一份,如果val的值沒有改變,那么操作系統(tǒng)本著不浪費(fèi)一點(diǎn)空間原則,直接使用val這個虛擬地址所對應(yīng)的物理地址就可以了。但是好景不長,子進(jìn)程把val修改掉了,所以操作系統(tǒng)就把子進(jìn)程val的虛擬地址所對應(yīng)的物理地址進(jìn)行了修改。從表面看起來好似地址沒有變,但是真實(shí)情況早都變化了。

C:進(jìn)程地址空間及作用

1:早期直接訪問物理內(nèi)存的缺陷所在

我們知道進(jìn)程=進(jìn)程控制塊PCB+代碼+數(shù)據(jù),早期計(jì)算機(jī),也就是沒有進(jìn)程地址空間的時(shí)候進(jìn)程一旦啟動,這些東西就會被全部裝入內(nèi)存,那么此時(shí)進(jìn)程訪問的就是真實(shí)的物理內(nèi)存,如果畫一張圖,應(yīng)該就是下面這樣

但是這樣防止有很大壞處:比如說野指針,放的這么近,一旦指針訪問的別的進(jìn)程的數(shù)據(jù),這就出了大亂子了。還有進(jìn)程在運(yùn)行過程中,是會產(chǎn)生數(shù)據(jù)的,產(chǎn)生的數(shù)據(jù)一旦不能放在本進(jìn)程后面,就要另外找內(nèi)存去存放,這樣就會導(dǎo)致不連續(xù)的現(xiàn)象,也增加了異常訪問的情況

2:進(jìn)程地址空間的發(fā)明

所以計(jì)算機(jī)設(shè)計(jì)者意識到了這種模式缺陷,想到了一種方法:增加一個中間層,利用中間層映射物理內(nèi)存。程序訪問內(nèi)存時(shí)不直接訪問物理內(nèi)存,先訪問中間層,如果中間層訪問沒有問題,那么操作系統(tǒng)就會將中間層映射到物理層,完成正常執(zhí)行

一個進(jìn)程創(chuàng)建之后,操作系統(tǒng)會為這個進(jìn)程分配一個專屬于它的大小為4GB的虛擬進(jìn)程地址空間(4GB是因?yàn)?2位系統(tǒng)中,指針是4個字節(jié)),與它相對的是一片真實(shí)的物理地址空間,操作系統(tǒng)在映射虛擬內(nèi)存時(shí)只會映射到那一片物理空間,而且需要特別注意這個虛擬空間并不是真的有4GB,它只是虛擬的 。由于每一個進(jìn)程都有自己的虛擬的進(jìn)程地址空間,所以它只能訪問自己的進(jìn)程的數(shù)據(jù),這樣做實(shí)現(xiàn)了隔離,也就是進(jìn)程之間的相互獨(dú)立。并且把虛擬地址空間劃分為這樣,那樣的區(qū),這樣的話也能解決數(shù)據(jù)的連續(xù)存放

3:頁表
不管怎樣,程序運(yùn)行一定要在物理內(nèi)存上,所以如何映射成為了關(guān)鍵,,這種映射稱為頁表
映射時(shí),讓虛擬地址和物理地址一一對應(yīng),進(jìn)程在虛擬地址上的地址就對應(yīng)了物理內(nèi)存上的某個地址。這樣的話就不存在非法訪問了,因?yàn)槊總€進(jìn)程都有自己獨(dú)立的進(jìn)程地址空間,如果非法訪問,頁表上根本就找不到這樣的地址,所以操作系統(tǒng)拒絕映射。“代碼,字符串是只讀的,數(shù)據(jù)是可讀可寫的”就是基于這個原因,雖然咋頁表上能找到,但是對代碼,字符串做了權(quán)限限制,一旦監(jiān)測到這些數(shù)據(jù)類型要做一些寫入操作,那么同樣操作系統(tǒng)拒絕映射

D:進(jìn)程地址空間如何工作

還是那個觀點(diǎn)“先描述,再組織”,也就是說我們看見的那個經(jīng)典的棧,堆分布圖,其實(shí)本質(zhì)也是一個結(jié)構(gòu)體,這個結(jié)構(gòu)體隸屬于task_struct,叫做task mm_struct(文件在mm_types.h)


這張圖可以說明task_stuct和task mm_struct的關(guān)系

申請空間的本質(zhì)就是想內(nèi)存索要空間,得到物理地址,然后在特定區(qū)域申請沒有使用的虛擬地址,建立映射關(guān)系,再返回虛擬地址

總結(jié)

以上是生活随笔為你收集整理的Linux系统编程14:进程入门之Linux进程中非常重要的概念之进程地址空间-原来我们看到的地址全部是虚拟的的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。