最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Linux進(jìn)程地址空間詳解

 更新時(shí)間:2025年02月20日 08:58:52   作者:s_little_monster_  
文章主要介紹了進(jìn)程地址空間和頁(yè)表的工作原理,以及它們?cè)诓僮飨到y(tǒng)中的作用,通過(guò)父子進(jìn)程的示例,解釋了進(jìn)程地址空間的共享和獨(dú)立性,以及頁(yè)表如何將虛擬地址轉(zhuǎn)換為物理地址,文章還討論了頁(yè)表的其他功能,如權(quán)限控制和頁(yè)面置換算法,并簡(jiǎn)要介紹了缺頁(yè)中斷的處理過(guò)程

一、程序地址空間

1、各內(nèi)存區(qū)域的相對(duì)位置

我記得在之前的博文中好像用編譯器粗略定位過(guò)各個(gè)類型地址空間的位置,這里我們?cè)衮?yàn)證一下它們的相對(duì)關(guān)系,這里是32位的機(jī)器,存儲(chǔ)空間為2^32byte=4GB

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int g_val_1;
int g_val_2 = 100;

int main(int argc, char *argv[], char *env[])
{
    printf("code addr: %p\n", main);//代碼段
    const char *str = "hello world";
    printf("read only string addr: %p\n", str);//只讀數(shù)據(jù)段
    printf("init global value addr: %p\n", &g_val_2);//數(shù)據(jù)段(已初始化)
    printf("uninit global value addr: %p\n", &g_val_1);//BBS段(未初始化)
    char *mem = (char*)malloc(100);
    char *mem1 = (char*)malloc(100);
    char *mem2 = (char*)malloc(100);
    //malloc在堆上開辟空間
    printf("heap addr: %p\n", mem);
    printf("heap addr: %p\n", mem1);
    printf("heap addr: %p\n", mem2);
    //臨時(shí)變量在棧上開辟空間
    printf("stack addr: %p\n", &str);
    printf("stack addr: %p\n", &mem);
    
    static int a = 0;
    int b;
    int c;
    //靜態(tài)成員變量在數(shù)據(jù)段
    printf("a = stack addr: %p\n", &a);
    //臨時(shí)變量在棧區(qū)
    printf("stack addr: %p\n", &b);
    printf("stack addr: %p\n", &c);
    //其實(shí)在棧區(qū)的最大地址處和內(nèi)核空間的最小地址處之間還有一部分
    //用來(lái)存放我們的命令行和環(huán)境變量,且環(huán)境變量在大地址處
    int i = 0;
    for(; argv[i]; i++)
        printf("argv[%d]: %p\n", i, argv[i]);

    for(i=0; env[i]; i++)
        printf("env[%d]: %p\n", i, env[i]);

    return 0;
}

從圖中我們可以看到,棧區(qū)和堆區(qū)是相對(duì)而生的,其中間有很大一部分的空間,在它們的中間還有一段內(nèi)存映射段,這里我們后面結(jié)合后面的內(nèi)容來(lái)解釋

2、引入父子進(jìn)程問(wèn)題

  • test
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
 
int g_val = 0;
 
int main()
{
    pid_t id = fork();
    if(id < 0)
    {
        perror("fork");
        return 0;
    }
    else if(id == 0)
    {
	 	//child
        printf("child[%d]: %d : %p\n", getpid(), g_val, &g_val);
    }
    else
    { 
		//parent
        printf("parent[%d]: %d : %p\n", getpid(), g_val, &g_val);
    }
    sleep(1);
    return 0;
}
  • fork_test
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int g_val = 0;
 
int main()
{
    pid_t id = fork();
    if(id < 0)
    {
        perror("fork");
        return 0;
    }
    else if(id == 0)
    {
	 	//child,子進(jìn)程先修改,完成之后,父進(jìn)程再讀取
        g_val=100;
        printf("child[%d]: %d : %p\n", getpid(), g_val, &g_val);
    }
    else
    { 
		//parent
        sleep(3);
        printf("parent[%d]: %d : %p\n", getpid(), g_val, &g_val);
    }
    sleep(1);
    return 0;
}

通過(guò)test進(jìn)程現(xiàn)象我們發(fā)現(xiàn),在這里我們的父子進(jìn)程在訪問(wèn)我們的g_val值時(shí)訪問(wèn)同一個(gè)位置同一個(gè)值,但是在我們子進(jìn)程對(duì)gal值進(jìn)行修改然后再讓父進(jìn)程進(jìn)行讀取的時(shí)候,我們發(fā)現(xiàn)父進(jìn)程讀取的值依舊是原來(lái)的g_val值,而子進(jìn)程讀取的值已經(jīng)是修改值,但地址還是相同的,地址相同怎么會(huì)讀取到不同的值呢?首先我們可以肯定的是,這個(gè)地址一定不是物理地址!同一塊物理地址訪問(wèn)到的值一定是一樣的!

結(jié)合我們?cè)谇懊嬷v到的,如果子進(jìn)程修改了數(shù)據(jù),我們會(huì)在另一塊位置重新開辟一塊空間用來(lái)存放子進(jìn)程與父進(jìn)程不同的這部分?jǐn)?shù)據(jù),這是為什么呢?這個(gè)實(shí)現(xiàn)的原理是什么呢?我們也可以肯定的是,這個(gè)變量,也就是這個(gè)數(shù)據(jù),內(nèi)容是不一樣的,這是我們觀察到的,父子進(jìn)程輸出的一定不是同一個(gè)變量!下面我們來(lái)討論一下

二、進(jìn)程地址空間

1、頁(yè)表

我們?cè)谥爸v到的程序地址空間的說(shuō)法其實(shí)是錯(cuò)誤的,正確來(lái)說(shuō)應(yīng)該叫進(jìn)程地址空間,上面我們所說(shuō)的地址叫做虛擬地址,也叫做線性地址,既然叫做虛擬地址,那當(dāng)然就不是真實(shí)的物理地址了,虛擬地址和物理地址存在映射關(guān)系,而承載他們映射關(guān)系的,就是頁(yè)表

我整理了一下地址空間、頁(yè)表和物理內(nèi)存的關(guān)系如下圖

在這個(gè)圖中,我們把父子進(jìn)程以及頁(yè)表分開來(lái)畫,因?yàn)樗鼈兪莾蓚€(gè)獨(dú)立的進(jìn)程,但是地址空間的這部分內(nèi)容是共享的,也就是虛擬地址是相同的,我們不是復(fù)制出了兩個(gè)地址空間,這里需要注意

內(nèi)核空間中有父子進(jìn)程的task_struct,它們里面有指向各自頁(yè)表的指針

其中上方是父進(jìn)程的地址空間,下方是子進(jìn)程的地址空間,子進(jìn)程直接復(fù)制父進(jìn)程的地址空間,包括虛擬地址、頁(yè)表等等變量都是相同的,類似于一個(gè)淺拷貝的過(guò)程,在子進(jìn)程修改g_val變量時(shí),子進(jìn)程在物理內(nèi)存上新開辟一塊空間,用來(lái)存放與父進(jìn)程數(shù)據(jù)不同的量,這個(gè)過(guò)程類似于memcpy的過(guò)程,創(chuàng)建并復(fù)制內(nèi)容,然后再將g_val改成100,然后頁(yè)表的物理地址指向該地址,這個(gè)過(guò)程是寫時(shí)拷貝,我們前面提到過(guò)

其中MMU起到的作用是負(fù)責(zé)將進(jìn)程虛擬地址轉(zhuǎn)換為物理地址,當(dāng) CPU 需要訪問(wèn)內(nèi)存時(shí),會(huì)將虛擬地址發(fā)送給 MMU,MMU 根據(jù)頁(yè)表等數(shù)據(jù)結(jié)構(gòu)進(jìn)行地址轉(zhuǎn)換,是與頁(yè)表息息相關(guān)的一個(gè)內(nèi)存管理單元

2、深入理解進(jìn)程地址空間

那看到這里有人問(wèn)了,地址空間究竟是什么啊,我們?yōu)槭裁匆M(jìn)行這樣的劃分?

我們一直拿32位的計(jì)算機(jī)舉例,因?yàn)樗粩?shù)少,比64位的計(jì)算機(jī)簡(jiǎn)單一些,這里的32位計(jì)算機(jī)又指的是什么?

在 32 位計(jì)算機(jī)里,地址總線寬度是 32 位,也就是有 32 條線路,每條線路能通過(guò)高低電平的轉(zhuǎn)換來(lái)實(shí)現(xiàn)0和1的變化,所以這 32 條線路能表示的不同地址組合數(shù)量為 2^32個(gè),因?yàn)槊總€(gè)內(nèi)存地址對(duì)應(yīng)一個(gè)字節(jié),所以 32 位計(jì)算機(jī)理論上能直接訪問(wèn)的內(nèi)存空間大小就是 2 ^32字節(jié),而2 ^32字節(jié)換算后等于 4GB,這就意味著 32 位計(jì)算機(jī)的 CPU 可以通過(guò)地址總線直接訪問(wèn)從 0 到 2 ^32 - 1地址范圍內(nèi)的 4GB 物理內(nèi)存

我們的進(jìn)程地址空間就在這樣一個(gè)概念中展開,而地址空間的劃分實(shí)際上是對(duì)該空間的一種組織,在正常運(yùn)行的情況下互不影響

我們計(jì)算機(jī)中最小的存儲(chǔ)單元就是字節(jié)byte,每個(gè)字節(jié)都會(huì)有一個(gè)地址,這個(gè)地址是可以直接被操作系統(tǒng)使用的,這是可以使用地址找到的最小單位,類似于bit這樣的存儲(chǔ)單元是沒(méi)有地址的概念的

所以所謂的進(jìn)程地址空間,本質(zhì)上是一個(gè)描述進(jìn)程可視范圍的大小,地址空間內(nèi)一定要存在各種區(qū)域的劃分,只要對(duì)虛擬地址(線性地址)進(jìn)行區(qū)域劃分即可

這里要注意的是,棧的start是高地址處,其他用戶空間都是start為低地址處

3、進(jìn)程地址空間這樣組織的優(yōu)勢(shì)

(一)讓進(jìn)程以一個(gè)統(tǒng)一的視角看待內(nèi)存

我們以頁(yè)表這樣的形式用來(lái)過(guò)渡,保證了我們所訪問(wèn)的虛擬地址(線性地址)是線性的,我們的進(jìn)程不管要做什么,我們只要知道它做的事情的性質(zhì),我們就知道它大概存儲(chǔ)在哪個(gè)線性地址區(qū)域,并且因?yàn)橛辛隧?yè)表的存在,我們不必再關(guān)心物理內(nèi)存的實(shí)際布局以及其他進(jìn)程的存在,我們本進(jìn)程只做好本進(jìn)程自己的事情就好了,其他的我并不關(guān)心

不同進(jìn)程的虛擬地址空間是相互隔離的,一個(gè)進(jìn)程無(wú)法直接訪問(wèn)另一個(gè)進(jìn)程的虛擬地址空間,這就保證了進(jìn)程之間的獨(dú)立性和安全性,一個(gè)進(jìn)程的錯(cuò)誤或惡意操作不會(huì)影響到其他進(jìn)程的正常運(yùn)行

(二)保護(hù)物理內(nèi)存

增加進(jìn)程虛擬地址空間可以讓我們?cè)L問(wèn)內(nèi)存的時(shí)候,增加一個(gè)轉(zhuǎn)換的過(guò)程,在這個(gè)轉(zhuǎn)換的過(guò)程中,可以對(duì)我們的尋址請(qǐng)求進(jìn)行審查,所以如果訪問(wèn)異常,就可以直接攔截,請(qǐng)求不會(huì)到達(dá)物理內(nèi)存,從而很好的保護(hù)了物理內(nèi)存不被攻擊

(三)進(jìn)程管理模塊和內(nèi)存管理模塊低耦合

我們通過(guò)頁(yè)表這個(gè)結(jié)構(gòu),很好地將進(jìn)程管理和內(nèi)存管理解耦合,互不影響,我們進(jìn)程所看到的只有虛擬地址,并不在乎物理地址如何如何,而我們的內(nèi)存也不需要在乎有多少進(jìn)程,進(jìn)程的作用是什么,而是只在需要的時(shí)候開辟和回收空間就可以了,這樣我們?cè)谶M(jìn)程出現(xiàn)問(wèn)題的時(shí)候不會(huì)影響到內(nèi)存管理,很好地阻斷了可能出現(xiàn)的一系列崩盤的問(wèn)題

4、頁(yè)表的其他內(nèi)容

頁(yè)表除了我們上面提到的作用以外,還存在類似讀寫權(quán)限這樣的功能,我們?cè)谥皩W(xué)習(xí)的時(shí)候,我們知道在只讀數(shù)據(jù)段中的數(shù)據(jù)是只可讀不可寫的,那么它相對(duì)應(yīng)的映射到物理內(nèi)存上,物理內(nèi)存上又沒(méi)有限制條件,它是怎么實(shí)現(xiàn)的只讀呢?其實(shí)是頁(yè)表的某一項(xiàng)屬性控制了該變量的讀寫,分為不可讀寫、可讀不可寫、可寫不可讀、可讀可寫,在映射的同時(shí)將該性質(zhì)傳遞回去,就只可讀了

其他的還有對(duì)應(yīng)代碼和數(shù)據(jù)是否已經(jīng)加載到內(nèi)存等等一系列的其他屬性

頁(yè)表的本質(zhì)屬于進(jìn)程的硬件上下文,在進(jìn)程切換的時(shí)候會(huì)帶走這些信息,被存儲(chǔ)在CPU寄存器中,task_struct中有指向頁(yè)表地址的指針

缺頁(yè)中斷

在虛擬內(nèi)存系統(tǒng)里,程序運(yùn)行時(shí)使用的是虛擬地址,虛擬地址空間會(huì)被劃分為多個(gè)頁(yè)面。物理內(nèi)存則被劃分為與虛擬頁(yè)大小相同的頁(yè)框。當(dāng)程序訪問(wèn)一個(gè)虛擬地址,而該地址對(duì)應(yīng)的頁(yè)面不在物理內(nèi)存中,也就是沒(méi)有被加載到物理內(nèi)存的頁(yè)框里時(shí),就會(huì)觸發(fā)缺頁(yè)中斷,這是一種特殊的中斷,它會(huì)暫停當(dāng)前程序的執(zhí)行,轉(zhuǎn)而去處理頁(yè)面加載的問(wèn)題

進(jìn)程剛開始運(yùn)行時(shí),它的代碼和數(shù)據(jù)所在的頁(yè)面可能都還沒(méi)有被加載到物理內(nèi)存中,當(dāng)進(jìn)程第一次訪問(wèn)某個(gè)頁(yè)面時(shí),就會(huì)因?yàn)樵擁?yè)面不在內(nèi)存而產(chǎn)生缺頁(yè)中斷;或者由于物理內(nèi)存資源有限,操作系統(tǒng)會(huì)使用頁(yè)面置換算法將一些暫時(shí)不用的頁(yè)面從物理內(nèi)存換出到磁盤的交換空間,當(dāng)進(jìn)程后續(xù)又需要訪問(wèn)這些被換出的頁(yè)面時(shí),就會(huì)觸發(fā)缺頁(yè)中斷

當(dāng)缺頁(yè)中斷發(fā)生時(shí),CPU 會(huì)保存當(dāng)前進(jìn)程的現(xiàn)場(chǎng)信息,包括程序計(jì)數(shù)器、寄存器等內(nèi)容,以便在中斷處理完成后能恢復(fù)進(jìn)程的執(zhí)行,操作系統(tǒng)根據(jù)引發(fā)缺頁(yè)中斷的虛擬地址,查找該頁(yè)面在磁盤上的位置,這通常需要借助頁(yè)表等數(shù)據(jù)結(jié)構(gòu)來(lái)確定頁(yè)面的磁盤地址,如果物理內(nèi)存中有空閑的頁(yè)框,操作系統(tǒng)會(huì)直接分配一個(gè)頁(yè)框;若沒(méi)有空閑頁(yè)框,就需要使用頁(yè)面置換算法選擇一個(gè)當(dāng)前在物理內(nèi)存中的頁(yè)面換出到磁盤,為即將要加載的頁(yè)面騰出空間,然后發(fā)出磁盤 I/O 請(qǐng)求,將所需的頁(yè)面從磁盤讀取到分配好的物理頁(yè)框中,頁(yè)面加載完成后,操作系統(tǒng)會(huì)更新頁(yè)表,將該虛擬頁(yè)與新分配的物理頁(yè)框建立映射關(guān)系,并設(shè)置相應(yīng)的標(biāo)志位,表示該頁(yè)面現(xiàn)在已經(jīng)在物理內(nèi)存中,最后,操作系統(tǒng)恢復(fù)之前保存的進(jìn)程現(xiàn)場(chǎng),讓進(jìn)程從產(chǎn)生缺頁(yè)中斷的指令處繼續(xù)執(zhí)行

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Linux如何查詢正在運(yùn)行的進(jìn)程對(duì)應(yīng)的可執(zhí)行文件所在目錄

    Linux如何查詢正在運(yùn)行的進(jìn)程對(duì)應(yīng)的可執(zhí)行文件所在目錄

    在Linux系統(tǒng)中,管理和監(jiān)控進(jìn)程是系統(tǒng)管理員和開發(fā)者的常見任務(wù),本文將整理Linux查詢正在運(yùn)行的進(jìn)程的多種方法,有需要的可以了解下
    2025-10-10
  • Nginx啟動(dòng)SSL功能,并進(jìn)行功能優(yōu)化詳細(xì)介紹

    Nginx啟動(dòng)SSL功能,并進(jìn)行功能優(yōu)化詳細(xì)介紹

    這篇文章主要介紹了Nginx啟動(dòng)SSL功能,并進(jìn)行功能優(yōu)化詳細(xì)介紹的相關(guān)資料,需要的朋友可以參考下
    2016-12-12
  • linux中rz上傳、sz下載命令詳解

    linux中rz上傳、sz下載命令詳解

    這篇文章主要介紹了linux中rz上傳、sz下載命令詳解的相關(guān)資料,需要的朋友可以參考下
    2018-08-08
  • 詳解CentOS 7.0源碼包搭建LNMP 實(shí)際環(huán)境搭建

    詳解CentOS 7.0源碼包搭建LNMP 實(shí)際環(huán)境搭建

    本篇文章主要介紹了Centos7+Nginx1.11.7+MySQL5.7.16+PHP7.1.0+openssl-1.1.0c,具有一定的參考價(jià)值,有興趣的可以了解一下。
    2016-12-12
  • Linux下刪除SVN版本庫(kù)的詳細(xì)過(guò)程

    Linux下刪除SVN版本庫(kù)的詳細(xì)過(guò)程

    在Linux系統(tǒng)中,刪除Subversion(SVN)版本庫(kù)是一個(gè)相對(duì)簡(jiǎn)單的過(guò)程,然而,在執(zhí)行刪除操作之前,確保你已經(jīng)備份了所有重要的數(shù)據(jù),因?yàn)閯h除操作是不可逆的,本文將指導(dǎo)你如何安全地刪除SVN版本庫(kù),需要的朋友可以參考下
    2025-02-02
  • linux如何為已存在的用戶創(chuàng)建home目錄

    linux如何為已存在的用戶創(chuàng)建home目錄

    這篇文章主要介紹了linux如何為已存在的用戶創(chuàng)建home目錄問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-04-04
  • Linux系統(tǒng)使用LVM掛載硬盤全過(guò)程

    Linux系統(tǒng)使用LVM掛載硬盤全過(guò)程

    文章介紹了在CentOS Linux 7.6上使用LVM配置新硬盤為邏輯卷的過(guò)程,包括確認(rèn)硬盤、創(chuàng)建分區(qū)、初始化物理卷、創(chuàng)建卷組、創(chuàng)建邏輯卷、格式化并掛載邏輯卷以及設(shè)置開機(jī)自動(dòng)掛載
    2025-11-11
  • Apache配置ProxyErrorOverride自定義錯(cuò)誤響應(yīng)的實(shí)現(xiàn)

    Apache配置ProxyErrorOverride自定義錯(cuò)誤響應(yīng)的實(shí)現(xiàn)

    本文主要介紹了Apache配置ProxyErrorOverride自定義錯(cuò)誤響應(yīng)的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2026-05-05
  • linux掛載以及初始化硬盤方式

    linux掛載以及初始化硬盤方式

    這篇文章主要介紹了linux掛載以及初始化硬盤方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-07-07
  • Linux日志查看和分析過(guò)程

    Linux日志查看和分析過(guò)程

    Linux日志是系統(tǒng)運(yùn)行狀態(tài)的重要記錄,包括系統(tǒng)啟動(dòng)、服務(wù)運(yùn)行、用戶操作和安全事件等信息,對(duì)于故障排查、安全審計(jì)和系統(tǒng)維護(hù)至關(guān)重要,文章詳細(xì)介紹了Linux日志的主要類型、存儲(chǔ)位置及作用,并提供了常用的查看和分析命令及工具
    2026-01-01

最新評(píng)論

垣曲县| 东至县| 上林县| 思南县| 康保县| 察雅县| 赤壁市| 南昌市| 武山县| 博乐市| 邯郸县| 益阳市| 靖江市| 高安市| 阿克苏市| 新龙县| 井陉县| 法库县| 四川省| 古交市| 安阳市| 夏津县| 迁西县| 渭源县| 启东市| 云安县| 聂荣县| 沧州市| 九台市| 长汀县| 陆川县| 永善县| 拉萨市| 斗六市| 且末县| 交口县| 兴仁县| 渭源县| 彭泽县| 六安市| 四子王旗|