物理內(nèi)存和虛擬內(nèi)存到底有什么區(qū)別?
? ??提到內(nèi)存,我們會(huì)想到經(jīng)常接觸的三個(gè)詞:虛擬內(nèi)存、物理內(nèi)存、共享內(nèi)存。它們分別對(duì)應(yīng)top輸出中的VIRT、RES、SHR三列。

? ? 1. 物理內(nèi)存
?? ??? 系統(tǒng)的物理內(nèi)存被劃分為許多相同大小的部分,也稱作內(nèi)存頁(yè)。內(nèi)存頁(yè)的大小取決于CPU的架構(gòu)和操作系統(tǒng)的配置,一般為4KB。物理內(nèi)存的使用主要分為以下幾方面:
? ? (1)內(nèi)核使用
?? ??? ?操作系統(tǒng)啟動(dòng)時(shí),位于/boot目錄下的壓縮內(nèi)核文件會(huì)被加載到內(nèi)存中并解壓。這部分內(nèi)容在系統(tǒng)允許期間都會(huì)常駐在內(nèi)存的起始位置。
? ? (2)slab分配器? ??? ?
?? ??? ?操作系統(tǒng)的運(yùn)行還需要更多的空間來(lái)分配給管理進(jìn)程、文件描述符、socket和加載的內(nèi)和模塊等內(nèi)容。所以內(nèi)核會(huì)通過(guò)slab分配器動(dòng)態(tài)分配內(nèi)存。
????????PS:slab是Linux操作系統(tǒng)的一種內(nèi)存分配機(jī)制。其工作是針對(duì)一些經(jīng)常分配并釋放的對(duì)象,如進(jìn)程描述符等,這些對(duì)象的大小一般比較小,如果直接采用brk系統(tǒng)調(diào)用來(lái)進(jìn)行分配和釋放,不僅會(huì)造成大量的碎片,而且也會(huì)影響性能。而slab分配器是基于對(duì)象進(jìn)行管理的,相同類型的對(duì)象歸為一類(如進(jìn)程描述符就是一類),每當(dāng)要申請(qǐng)這樣一個(gè)對(duì)象,slab分配器就從一個(gè)slab列表中分配一個(gè)這樣大小的單元出去,而當(dāng)要釋放時(shí),將其重新保存在該列表中,而不是直接返回給操作系統(tǒng),從而避免這些出現(xiàn)內(nèi)存碎片。slab分配器并不丟棄已分配的對(duì)象,而是釋放并把它們保存在內(nèi)存中。當(dāng)以后又要請(qǐng)求新的對(duì)象時(shí),就可以從內(nèi)存直接獲取而不用重復(fù)初始化??梢栽?proc/meminfo中查看當(dāng)前slab分配器中的內(nèi)存大小。

? ? ?(3)進(jìn)程使用? ??? ??
????????除去內(nèi)核使用的部分,所有的進(jìn)程都需要分配物理內(nèi)存頁(yè)給它們的代碼、數(shù)據(jù)和堆棧。進(jìn)程消耗的這些物理內(nèi)存被稱為“駐留內(nèi)存”,RSS。
? ? ?(4)頁(yè)緩存page cache
?? ?? ? 除去在內(nèi)核和進(jìn)程使用的部分,物理內(nèi)存剩下的部分被稱為頁(yè)緩存,page cache。因?yàn)榇疟P(pán)io的速度遠(yuǎn)遠(yuǎn)低于內(nèi)存的訪問(wèn)速度,所以為了加快訪問(wèn)磁盤(pán)數(shù)據(jù)的速度,頁(yè)緩存盡可能的保存著從磁盤(pán)讀入的數(shù)據(jù)。page cache中還有一部分稱為buffer,它的作用是緩存要寫(xiě)入到磁盤(pán)的數(shù)據(jù)。
?? ?? ? 頁(yè)緩存的大小是在一直動(dòng)態(tài)變化的。當(dāng)系統(tǒng)內(nèi)存充足時(shí),頁(yè)緩存會(huì)一直增大;當(dāng)系統(tǒng)free內(nèi)存不足時(shí),這時(shí)如果有進(jìn)程申請(qǐng)內(nèi)存,操作系統(tǒng)會(huì)從page cache中回收內(nèi)存頁(yè)進(jìn)行分配,如果page cache也已不足,那么系統(tǒng)會(huì)將當(dāng)期駐留在內(nèi)存中的數(shù)據(jù)置換到事先配置在磁盤(pán)上的swap空間中,然后空出來(lái)的這部分內(nèi)存就可以用來(lái)分配了。這就是swap交換。
?? ?? ? PS:出現(xiàn)swap交換時(shí),數(shù)據(jù)被置換到swap空間后(swap out),該進(jìn)程使用的內(nèi)存量下降,在atop等監(jiān)控工具中的RGROW列為負(fù)值,但這并不表示該進(jìn)程釋放了內(nèi)存,當(dāng)它需要時(shí),這部分?jǐn)?shù)據(jù)又會(huì)被換入到內(nèi)存中(swap in)。另外, swap交換往往會(huì)帶來(lái)磁盤(pán)IO的大量消耗,嚴(yán)重影響到系統(tǒng)正常的磁盤(pán)io。出現(xiàn)大量的swap交換說(shuō)明系統(tǒng)已經(jīng)快要不行了,需要重點(diǎn)關(guān)注。
????2. 虛擬內(nèi)存
?? ?? ?顧名思義,虛擬內(nèi)存實(shí)際上并不存在,它只是存在于這套巧妙的內(nèi)存管理機(jī)制中。當(dāng)一個(gè)進(jìn)程啟動(dòng)時(shí),內(nèi)核會(huì)給新的進(jìn)程建立一個(gè)虛擬地址空間。這個(gè)虛擬地址空間代表了該進(jìn)程可能使用到的所有內(nèi)存,當(dāng)然它是可以動(dòng)態(tài)變化的。虛擬地址結(jié)構(gòu)示意圖如下,從下往上地址增大,主要包括以下幾個(gè)部分:
? ? ? ? (1)代碼段:該部分只讀,用于存放加載的代碼。
? ? ? ? (2)數(shù)據(jù)段:用于存放全局變量和靜態(tài)變量。
? ? ? ? (3)堆:動(dòng)態(tài)內(nèi)存,當(dāng)malloc/free申請(qǐng)釋放內(nèi)存小于某個(gè)閾值(一般操作系統(tǒng)設(shè)定為128K,可以修改)時(shí),通過(guò)brk/sbrk系統(tǒng)調(diào)用,控制堆頂指針向高地址偏移(malloc)或者低地址偏移(free)。
? ? ? ? (4)文件映射區(qū):動(dòng)態(tài)內(nèi)存,當(dāng)malloc/free申請(qǐng)釋放內(nèi)存大于128K時(shí),通過(guò)mmap系統(tǒng)調(diào)用分配一塊虛擬地址空間。
? ? ? ? (5)棧:用于存放局部變量和進(jìn)程上下文。

????????看到這里可能會(huì)產(chǎn)生一個(gè)疑問(wèn):既然都有了物理內(nèi)存,為什么還要有虛擬內(nèi)存呢?這是因?yàn)橛捎诔杀镜南拗?,物理?nèi)存往往無(wú)法做的很大,但是進(jìn)程運(yùn)行階段所需申請(qǐng)的內(nèi)存可能遠(yuǎn)遠(yuǎn)超過(guò)物理內(nèi)存,并且系統(tǒng)不可能只跑一個(gè)進(jìn)程,會(huì)有多個(gè)進(jìn)程一起申請(qǐng)使用內(nèi)存,如果都直接向物理內(nèi)存進(jìn)行申請(qǐng)使用肯定無(wú)法滿足。通過(guò)引入虛擬內(nèi)存,每個(gè)進(jìn)程都有自己獨(dú)立的虛擬地址空間,這個(gè)空間理論上可以無(wú)限大,因?yàn)樗⒉灰X(qián)。一個(gè)進(jìn)程同一時(shí)刻不可能所有變量數(shù)據(jù)都會(huì)訪問(wèn)到,只需要在訪問(wèn)某部分?jǐn)?shù)據(jù)時(shí),把這一塊虛擬內(nèi)存映射到物理內(nèi)存,其他沒(méi)有實(shí)際訪問(wèn)過(guò)的虛擬地址空間并不會(huì)占用到物理內(nèi)存,這樣對(duì)物理內(nèi)存的消耗就大大減少了 。
? ??????虛擬內(nèi)存->物理內(nèi)存的映射機(jī)制
? ??????系統(tǒng)內(nèi)核為每個(gè)進(jìn)程都維護(hù)了一份從虛擬內(nèi)存到物理內(nèi)存的映射表,稱為頁(yè)表。頁(yè)表根據(jù)虛擬地址,查找出鎖映射的物理頁(yè)位置和數(shù)據(jù)在物理頁(yè)中的偏移量,便得到了實(shí)際需要訪問(wèn)的物理地址。(具體的多級(jí)頁(yè)表實(shí)現(xiàn)本文不深入探討)
? ??????如下圖所示:

? ??????? ? 這里還要提到一個(gè)概念,駐留內(nèi)存,這是指虛擬內(nèi)存中實(shí)際映射到物理內(nèi)存的那部分,也就是進(jìn)程實(shí)際占用的物理內(nèi)存大小。所以判斷一個(gè)進(jìn)程使用的內(nèi)存大小,主要是看占用的物理內(nèi)存,也就是駐留內(nèi)存的大小,即RSS。
? ? ? 3. 共享內(nèi)存
? ?????進(jìn)程在運(yùn)行過(guò)程中,會(huì)加載許多操作系統(tǒng)的動(dòng)態(tài)庫(kù),比如 libc.so、libld.so等。這些庫(kù)對(duì)于每個(gè)進(jìn)程而言都是公用的,它們?cè)趦?nèi)存中實(shí)際只會(huì)加載一份,這部分稱為共享內(nèi)存。如上圖中的A4和B3部分即為共享內(nèi)存,實(shí)際都映射到同一塊物理內(nèi)存。
? ? 注意,進(jìn)程占用的共享內(nèi)存也是計(jì)算到駐留內(nèi)存中的。