Linux內存佈局

咱們先來看下Linux內存佈局,此圖比我以前寫的那篇文章寫的佈局更詳細html

在linux中,每個進程都被抽象爲task_struct結構體,稱爲進程描述符,存儲着進程linux

各方面的信息;例如打開的文件,信號以及內存等等;而後task_struct的一個屬性mm_struct管理着進程的全部虛擬內存,稱爲內存描述符。在mm_struct結構體中,存儲着進程各個內存段的開始以及結尾,如上圖所示;這個進程使用的物理內存,即常駐內存RSS頁數,這個內存使用的虛擬地址空間VSZ頁數,還有這個進程虛擬內存區域集合和頁表。緩存

從上面這個圖能夠看出,進程是有代碼段Text segment,數據段(已初始化的全局,靜態變量),BSS段(未初始化的全局,靜態變量),堆,內存映射區以及棧;函數

每一塊虛擬內存區(VMA)都是由一塊連續的虛擬地址組成,這些地址從不覆蓋。一個vm_area_struct實例描述了一塊內存區域,包括這塊內存區域的開始以及結尾地址;flags標誌決定了這塊內存的訪問權限和行爲;vm_file決定這塊內存是由哪一個文件映射的,若是沒有文件映射,則這塊內存爲匿名的(anonymous)。上述圖中提到的每一個內存段,都對應於一個vm_area_struct結構。以下圖所示佈局

上圖即爲/bin/gonzo進程的內存佈局。程序的二進制文件映射到代碼段和數據段,代碼段爲只讀只執行,不可更改;全局以及靜態的未初始化的變量映射到BSS段,爲匿名映射,堆和棧也是匿名映射,由於沒有相應的文件映射;內存映射區能夠映射共享庫,映射文件以及匿名映射,因此這塊內存段能夠是文件映射也能夠是匿名映射。並且不一樣的文件,映射到不一樣的vm_area_struct區。指針

這些vm_area_struct集合存儲在mm_struct中的一個單向鏈表和紅黑樹中;當輸出/proc/pid/maps文件時,只須要遍歷這個鏈表便可。紅黑樹主要是爲了快速定位到某一個內存塊,紅黑樹的根存儲在mm_rb域。htm

以前介紹過,線性地址須要經過頁表才能轉換爲物理地址。每一個進程的內存描述符也保存了這個進程頁表指針pgd,每一塊虛擬內存頁都和頁表的某一項對應。blog

虛擬內存是不存儲任何數據的,它只是將地址空間映射到物理內存。物理內存有內核夥伴系統分配,若是一塊物理內存沒有被映射,就能夠被夥伴系統分配給虛擬內存。剛分配的物理內存葉框多是匿名的,存儲進程數據,也多是也緩存,存儲文件或塊設備的數據。一塊虛擬內存vm_area_struct塊是由連續的虛擬內存頁組成的,而這些虛擬內存塊映射的物理內存卻不必定連續,以下圖所示:進程

如上圖所示,有三個頁映射到物理內存,還有兩個頁沒有映射,因此常駐內存RSS爲12kb,而虛擬內存大小爲20kb。對於有映射到物理內存的三個頁的頁表項PTE的Present標誌設爲1,而兩個沒有映射物理內存的虛擬內存頁表項的Present位清除。因此這時訪問那兩塊內存,則會致使異常缺頁。內存

vma就像應用程序和內核的一個契約。當應用程序申請內存或者文件映射時,內核先響應這個請求,分配或更新虛擬內存;可是這些虛擬內存並無映射到真實的物理內存。而是等到內存訪問產生一個內存異常缺頁時才真正映射物理內存。即當訪問沒有映射的虛擬內存時,因爲頁表項的Present位沒有被設置,因此此時會產生一個缺頁異常。vma記錄和頁表項兩個在解決內存缺頁,釋放內存以及內存swap out都起着重要的做用。下面圖展現了上述狀況:

一、一開始堆中只有8kb的內存,並且都已經映射到物理內存;

二、當調用brk()函數擴展堆時,新的頁是沒有映射到物理內存的,

三、當處理器須要訪問一個地址,並且這個地址在上述剛分配的虛擬內存中,這時產生一個缺頁異常;

四、這時進程向夥伴系統申請一頁的物理內存,映射到那塊虛擬內存上,並添加頁表項,設置Present位.

自此,這個內存管理暫時就說到這。總結下:

一、Linux進程的內存佈局的每一個段都是有一個vm_area_struct,而這個實例是由連續的虛擬內存地址組成;

二、當請求內存時,先是擴展vm_area_struct或者新分配一個vm_area_struct,可是並不映射物理內存,只有等到訪問這塊內存時,產生缺頁異常,內核才分配物理內存。

本文地址:https://www.linuxprobe.com/linux-memory-layout.html

相關文章
相關標籤/搜索