上講中,講解了linux的物理內存管理,這講進行虛擬內存管理的講解。
咱們程序猿們常常講「我new(malloc)了多少內存」,實際上咱們使用的new(malloc)申請的內存是「虛擬內存」,更確切的說,咱們程序猿(app程序猿,不是寫內核的)所能操控的都是「虛擬內存」。
什麼是「虛擬內存」?就是這個「內存」不是指真正內存條的,而是操做系統給你開的一個空頭支票。尼瑪?這是怎麼回事?是否是有點暈?沒事,我給你們舉個例子。
假設有個銀行,銀行只有1000w,誰須要錢就向銀行借,後續只需還本金不用還利息(現實中要有這麼好就行了)。假設每一個人一輩子下來,銀行就給他開個1000w的支票且不能直接使用支票,但銀行並不會立刻給他1000w,等到他用錢的時候,銀行就給他實際須要的數目,若是銀行暫時沒有那麼多,就讓他等等。可是通常人都不會一次性須要那麼多錢,這樣基本上每一個人取錢的時候,銀行通常都會知足,讓每一個人感受他都有1000w可用。
操做系統就好像上面例子中的銀行,物理內存就好像錢,虛擬內存就是銀行開出的支票。當咱們app啓動時,操做系統就分給它4G虛擬內存(32位),等到app實際須要內存時,操做系統才分配真正的物理內存給它,這樣每一個app都感受它擁有4G內存。
爲何要有虛擬內存呢?
個人理解是:方便管理,安全。
若是每一個app直接去操做物理內存,因爲只有一塊物理內存,那每一個程序起始的物理地址就不同,比較麻煩,有了虛擬內存,你們的起始地址都同樣,方便管理;再就是安全,有了虛擬內存,app只能操做虛擬內存,物理內存由內核統一安排,這樣不至於某個app出了問題,把別的app的內存數據給覆蓋,影響另外一個app。
如今應該看看虛擬內存的地址空間了(32位的):
java
虛擬地址空間整體上分爲兩大部分:內核空間(1G)和用戶空間(3G)。咱們的app能操做的虛擬地址就是用戶空間部分。
內核空間:內核空間大致上又可分爲兩部分,3G~3G+896M,這部分到物理地址的映射是寫死的,畢竟總得有內核本身的代碼也是要加載到物理內存中才能執行啊!(這也說明,程序中的初始化是一個程序很是重要的部分,從此遇到開源程序,先看它的初始部分,不然會看暈的)
用戶空間:用戶空間通常有3G,又可細分爲:stack、mmap、heap、bss、data、text等部分。
stack:比較常見,就是咱們平時說的棧,內存的釋放不須要咱們管理;
mmap:這裏通常是將咱們要讀的文件映射進來,實現文件的直接讀寫;
heap:就是咱們日常說的堆, c/c++中的new、malloc就是在這個範圍內分配,須要咱們程序管理釋放。
bss:一般是指用來存放程序中未初始化的全局變量的一塊內存區域。
data:一般是指用來存放程序中已初始化的全局變量的一塊內存區域。
text:一般是指用來存放程序執行代碼的一塊內存區域。
用戶空間的這些劃分都是邏輯上的,內核代碼中使用memory region對象實際管理整個虛擬地址空間,結構爲vm_area_struct。一個進程中可能有多個memory region,每一個memory region表明了一段地址空間範圍。全部memory region以鏈表的形式鏈接在一塊兒(同時也以紅黑樹的結構存儲,爲了快速定位一個具體的地址)。
memory region和上面將的stack、heap等是模糊對應的,例如bss、heap等有可能在同一個memory region上。
講到這裏,基本上把虛擬內存與物理內存的關係,以及虛擬內存的做用將清楚了(有不清楚的,能夠下來直接找我)。如今就應該講講內核中是怎麼把虛擬內存映射到物理內存的(畢竟支票沒法使用)。
通過編譯後的程序中的地址都是虛擬地址,cpu再執行這個命令以前必須把虛擬地址轉換爲物理地址,這個轉換使用的就是頁表,每一個app都有本身的頁表。linux爲了高度抽象化,規定頁表有四級:
頁全局目錄PGD、頁上級目錄PUD、頁中間目錄PMD和頁表PT。以下圖所示:(具體轉換不作介紹,網上比較多,你們能夠查閱)
linux
講到這裏,你們彷佛感受到:一個程序要使用內存,必須先申請虛擬內存,而後操做系統纔給你分配物理內存。you are right!!!程序中分配虛擬內存的接口爲new(c++)、malloc(c)。java中不須要咱們本身操做,是由jvm向操做系統申請的。
本貼只將了基本性的概念,具體你們能夠分塊查詢,學習。c++