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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux 进程地址空间的一步步探究

發布時間:2025/3/19 linux 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux 进程地址空间的一步步探究 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

我們知道,在32位機器上linux操作系統中的進程的地址空間大小是4G,其中0-3G是用戶空間,3G-4G是內核空間。其實,這個4G的地址空間是不存在的,也就是我們所說的虛擬內存空間。

那虛擬內存空間是什么呢,它與實際物理內存空間又是怎樣對應的呢,為什么有了虛擬內存技術,我們就能運行比實際物理內存大的應用程序,它是怎么做到的呢?呵呵,這一切的一切都是個迷呀,下面我們就一步一步解開心中的謎團吧!

進程使用虛擬內存中的地址,由操作系統協助相關硬件,把它“轉換”成真正的物理地址。虛擬地址通過頁表(Page Table)映射到物理內存,頁表由操作系統維護并被處理器引用。內核空間在頁表中擁有較高特權級,因此用戶態程序試圖訪問這些頁時會導致一個頁錯誤(page fault)。在Linux中,內核空間是持續存在的,并且在所有進程中都映射到同樣的物理內存。內核代碼和數據總是可尋址,隨時準備處理中斷和系統調用。與此相反,用戶模式地址空間的映射隨進程切換的發生而不斷變化。

? ? ?Linux進程在虛擬內存中的標準內存段布局如下圖所示:

我們來看看,當我們寫好一個應用程序,編譯后它都有什么東東?

例如:

用命令size a.out會得到:

其中text是放的是代碼,data放的是初始化過的全局變量或靜態變量,bss放的是未初始化的全局變量或靜態變量。

由于歷史原因,C程序一直由下列幾部分組成:

A、正文段。這是由cpu執行的機器指令部分。通常,正文段是可共享的,所以即使是經常執行的程序(如文本編輯程序、C編譯程序、shell等)在存儲器中也只需要有一個副本,另外,正文段常常是只讀的,以防止程序由于意外事故而修改器自身的指令。

B、初始化數據段。通常將此段稱為數據段,它包含了程序中需賦初值的變量。例如,C程序中任何函數之外的說明:

int maxcount = 99;(全局變量)

C、非初始化數據段。通常將此段稱為bss段,這一名稱來源于早期匯編程序的一個操作,意思是"block started by symbol",在程序開始執行之前,內核將此段初始化為0。函數外的說明:

long sum[1000];

使此變量存放在非初始化數據段中。

D、棧。自動變量以及每次函數調用時所需保存的信息都存放在此段中。每次函數調用時,其返回地址、以及調用者的環境信息(例如某些機器寄存器)都存放在棧中。然后,新被調用的函數在棧上為其自動和臨時變量分配存儲空間。通過以這種方式使用棧,C函數可以遞歸調用。

E、堆。通常在堆中進行動態存儲分配。由于歷史上形成的慣例,堆位于非初始化數據段頂和棧底之間。

從上圖我們看到棧空間是下增長的,堆空間是從下增長的,他們會會碰頭呀?一般不會,因為他們之間間隔很大,如:

     #include <stdio.h>#include <stdlib.h>int bss_var;int data_var0 = 1;int main(){printf("Test location:\n");printf("\tAddress of main(Code Segment):%p\n",main);printf("_____________________________________\n");int stack_var0 = 2;printf("Stack location:\n");printf("\tInitial end of stack:%p\n",&stack_var0);int stack_var1 = 3;printf("\tNew end of stack:%p\n",&stack_var1);printf("_____________________________________\n");printf("Data location:\n");printf("\tAddress of data_var(Data Segment):%p\n",&data_var0);static int data_var1 = 4;printf("\tNew end of data_var(Data Segment):%p\n",&data_var1);printf("_____________________________________\n");printf("BSS location:\n");printf("\tAddress of bss_var:%p\n",&bss_var);printf("_____________________________________\n");printf("Heap location:\n");char *p = (char *)malloc(10);printf("\tAddress of head_var:%p\n",p);return 0;}

運行結果如下:

呵呵,這里我們看到地址了,這個地址是虛擬地址,這些地址時怎么來的呢?其實在我們編譯的時候,這些地址就已經確定了,如下圖中紅線。

也就是說,我們不論我們運行a.out程序多少次這些地址都是一樣的。我們知道,linux操作系統每個進程的地址空間都是獨立的,其實這里的獨立說得是物理空間上得獨立。進程可以使用相同的虛擬地址,這不奇怪,因為轉換后的物理地址并非相同的。相同的虛擬地址,不同的物理地址,他們之間是怎樣聯系起來的呢?我們繼續探究....

在linux操作系統中,每個進程都通過一個task_struct的結構體描敘,每個進程的地址空間都通過一個mm_struct描敘,c語言中的每個段空間都通過vm_area_struct表示,他們關系如下 :

運行一個程序時,操作系統需要創建一個進程,這個進程和程序之間都干了些什么呢?

當一個程序被執行時,該程序的內容必須被放到進程的虛擬地址空間(注意,是虛擬地址空間),對于可執行程序的共享庫也是如此。可執行程序并非真正讀到物理內存中,而只是鏈接到進程的虛擬內存中(此時都是在進程的虛擬地址空間)。

當一個可執行程序映射到進程虛擬地址空間時,一組vm_area_struct數據結構將被產生。每個vm_area_struct數據結構表示可執行印象的一部分;是可執行代碼,或是初始化的數據,以及未初始化的數據等。

linux操作系統是通過sys_exec對可執行文件進行映射以及讀取的,有如下幾步:

1、創建一組vm_area_struct;

2、圈定一個虛擬用戶空間,將其起始結束地址(elf段中已設置好)保存到vm_start和vm_end中

3、將磁盤file句柄保存在vm_file中;

4、將對應段在磁盤file中的偏移值(elf段中已設置好)保存在vm_pgoff中;

5、將操作該磁盤file的磁盤操作函數保存在vm_ops中;

注意:這里沒有對應 的頁目錄表項創建頁表,更不存在設置頁表項了

假設現在程序中有一條指令需要讀取上面vm_start--vm_end之間的某內容

例如:mov [0x08000011],%eax,那么將會執行如下序列:

1、cpu依據CR3(current->pgd)找到0x08000011地址對應的pgd[i],由于該pgd[i]內容保持為初始化狀態即為0,導致cpu異常。

2、.do_page_fault被調用,在該函數中,為pgd[i]在內存中分配一個頁表,并讓該表項指向它,如下圖所示:

注意:這里i為0x08000011高10位,j為其中間10位,此時pt表項全部為0(pte[j]也為0);

3、為pte[j]分配一個真正的物理內存頁面,依據vm_area_struct中的vm_file、vm_pgoff和vm_ops,調用filemap_nopage將磁盤file中vm_pgoff偏移處的內容讀入到該物理頁面中,如下圖所示:

分配物理內存頁面

從磁盤文件中將內容讀取到物理內存頁面中

從上面我們可以知道,在進程創建的過程中,程序內容被映射到進程的虛擬內存空間,為了讓一個很大的程序在有限的物理內存空間運行,我們可以把這個程序的開始部分先加載到物理內存空間運行,因為操作系統處理的是進程的虛擬地址,如果在進行虛擬到物理地址的轉換工程中,發現物理地址不存在時,這個時候就會發生缺頁異常(nopage),接著操作系統就會把磁盤上還沒有加載到內存中的數據加載到物理內存中,對應的進程頁表進行更新。也許你會問,如果此時物理內存滿了,操作系統將如何處理?

下面我們看看linux操作系統是如何處理的:

如果一個進程想將一個虛擬頁裝入物理內存,而又沒有可使用的空閑物理頁,操作系統就必須淘汰物理內存中的其他頁來為此頁騰出空間。

在linux操作系統中,物理頁的描敘如下:

struct mem_map

{

1、本頁使用計數,當該頁被許多進程共享時計數將大于1

2、age描敘本頁的年齡,用來判斷該頁是否為淘汰或交換的好候選

3、map_nr描敘物理頁的頁幀號

}

如果從物理內存中被淘汰的頁來自于一個映像或數據文件,并且還沒有被寫過,則該頁不必保存,它可以丟掉。如果有進程在需要該頁時就可以把它從映像或數據文件中取回內存。

然而,如果該頁被修改過,操作系統必須保留該頁的內容以便晚些時候在被訪問。這種頁稱為"臟(dirty)頁",當它被從內存中刪除時,將被保存在一個稱為交換文件的特殊文件中。

相對于處理器和物理內存的速度,訪問交換文件要很長時間,操作系統必須在將頁寫到磁盤以及再次使用時取回內存的問題上花費心機。

如果用來決定哪一頁被淘汰或交換的算法不夠高效的話,就可能出現稱為"抖動"的情況。在這種情況下,頁面總是被寫到磁盤又讀回來,操作系統忙于此而不能進行真正的工作。

linux使用"最近最少使用(Least Recently Used ,LRU)"頁面調度技巧來公平地選擇哪個頁可以從系統中刪除。這種設計系統中每個頁都有一個"年齡",年齡隨頁面被訪問而改變。頁面被訪問越多它越年輕;被訪問越少越老。年老的頁是用于交換的最佳候選頁。

?

總結

以上是生活随笔為你收集整理的linux 进程地址空间的一步步探究的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 一区二区高清在线 | 天天综合天天 | 精品一区在线视频 | 黄色免费网站在线看 | 亚洲欧洲国产日韩 | 香港一级淫片免费放 | www视频免费在线观看 | 成人精品视频一区二区 | 在线免费观看亚洲视频 | 日韩亚洲视频在线观看 | 亚洲天堂小视频 | 九九热精品视频在线观看 | 啪啪免费网 | 色偷偷免费视频 | www.亚洲色图 | 97激情| 99精品视频国产 | 国产影音先锋 | 日韩美女中文字幕 | 色悠悠网址 | 久久久久午夜 | 综合色99 | 欧美性生活一区二区三区 | 日韩一区在线观看视频 | h片在线播放 | 国产精品理论在线观看 | 国产精品久久久久久久久久东京 | 美女张开双腿让男人捅 | av片国产| 欧美 日韩 国产 成人 在线观看 | 天堂网av2014 | 女性向av免费网站 | 成人国产一区二区三区精品麻豆 | 色亭亭 | 欧美日韩黄色大片 | 91精品国产一区二区三竹菊影视 | 麻豆成人免费视频 | 日韩av少妇| 伊人99热 | 欧美日韩精品久久久 | 在线观看一级片 | 亚洲国产欧美一区二区三区深喉 | wwwwww日本 | 99re6这里只有精品 | 亚洲啊v| 日韩有码一区二区三区 | 成人黄色电影在线 | 中文字幕黑丝 | 久久久精品中文字幕麻豆发布 | 久久99久久精品 | 色播基地| 老司机深夜福利视频 | 欧美韩一区二区 | 30一40一50老女人毛片 | 亚洲天堂一 | 91精品国产91久久久久青草 | 天天射网 | 美女性高潮视频 | 在线中文字幕播放 | 91精品人妻一区二区三区果冻 | 男人的天堂欧美 | 天堂√8在线中文 | 免费做a爰片77777 | 免费国产在线观看 | 天天插av | 卡通动漫精品一区二区三区 | 日本免费黄色网 | 色老头在线观看 | 久久亚洲少妇 | 日韩在线观看你懂的 | 中文字幕高清视频 | 欧美成人精品欧美一级乱黄 | 精品国产系列 | 91中文字幕在线视频 | 欧美激情片一区二区 | 影音先锋婷婷 | 亚洲国产精品久久久久婷婷老年 | 国产精品高潮呻吟久久久久久 | av电影免费在线播放 | 国产亚洲精品成人av久久ww | 欧美一区二区在线视频观看 | 啊灬啊灬啊灬秀婷 | 密臀av一区二区 | 男人午夜av | 葵司有码中文字幕二三区 | 中午字幕在线观看 | 久久久久久无码精品大片 | 激情国产在线 | 免费av网站在线看 | 蜜桃91丨九色丨蝌蚪91桃色 | 日韩一级伦理片 | 亚洲色图制服丝袜 | 香蕉久久精品日日躁夜夜躁 | 亚洲精品在线一区二区 | 亚洲国产黄色片 | 在线视频1卡二卡三卡 | 一区二区三区视频免费在线观看 | 欧美日韩三级视频 | 国产精成人 |