物理内存和虛拟内存到底有什麼區别?
提到内存,我們會想到經常接觸的三個詞:虛拟内存、物理内存、共享内存。它們分别對應top輸出中的VIRT、RES、SHR三列。
1. 物理内存
系統的物理内存被劃分為許多相同大小的部分,也稱作内存頁。内存頁的大小取決于CPU的架構和操作系統的配置,一般為4KB。物理内存的使用主要分為以下幾方面:
操作系統啟動時,位于/boot目錄下的壓縮内核文件會被加載到内存中并解壓。這部分内容在系統允許期間都會常駐在内存的起始位置。
操作系統的運行還需要更多的空間來分配給管理進程、文件描述符、socket和加載的内和模塊等内容。所以内核會通過slab分配器動态分配内存。
PS:slab是Linux操作系統的一種内存分配機制。其工作是針對一些經常分配并釋放的對象,如進程描述符等,這些對象的大小一般比較小,如果直接采用brk系統調用來進行分配和釋放,不僅會造成大量的碎片,而且也會影響性能。而slab分配器是基于對象進行管理的,相同類型的對象歸為一類(如進程描述符就是一類),每當要申請這樣一個對象,slab分配器就從一個slab列表中分配一個這樣大小的單元出去,而當要釋放時,将其重新保存在該列表中,而不是直接返回給操作系統,從而避免這些出現内存碎片。slab分配器并不丢棄已分配的對象,而是釋放并把它們保存在内存中。當以後又要請求新的對象時,就可以從内存直接獲取而不用重複初始化。可以在/proc/meminfo中查看當前slab分配器中的内存大小。
除去内核使用的部分,所有的進程都需要分配物理内存頁給它們的代碼、數據和堆棧。進程消耗的這些物理内存被稱為“駐留内存”,RSS。
除去在内核和進程使用的部分,物理内存剩下的部分被稱為頁緩存,page cache。因為磁盤io的速度遠遠低于内存的訪問速度,所以為了加快訪問磁盤數據的速度,頁緩存盡可能的保存着從磁盤讀入的數據。page cache中還有一部分稱為buffer,它的作用是緩存要寫入到磁盤的數據。
頁緩存的大小是在一直動态變化的。當系統内存充足時,頁緩存會一直增大;當系統free内存不足時,這時如果有進程申請内存,操作系統會從page cache中回收内存頁進行分配,如果page cache也已不足,那麼系統會将當期駐留在内存中的數據置換到事先配置在磁盤上的swap空間中,然後空出來的這部分内存就可以用來分配了。這就是swap交換。
PS:出現swap交換時,數據被置換到swap空間後(swap out),該進程使用的内存量下降,在atop等監控工具中的RGROW列為負值,但這并不表示該進程釋放了内存,當它需要時,這部分數據又會被換入到内存中(swap in)。另外, swap交換往往會帶來磁盤IO的大量消耗,嚴重影響到系統正常的磁盤io。出現大量的swap交換說明系統已經快要不行了,需要重點關注。
顧名思義,虛拟内存實際上并不存在,它隻是存在于這套巧妙的内存管理機制中。當一個進程啟動時,内核會給新的進程建立一個虛拟地址空間。這個虛拟地址空間代表了該進程可能使用到的所有内存,當然它是可以動态變化的。虛拟地址結構示意圖如下,從下往上地址增大,主要包括以下幾個部分:
(1)代碼段:該部分隻讀,用于存放加載的代碼。
(2)數據段:用于存放全局變量和靜态變量。
(3)堆:動态内存,當malloc/free申請釋放内存小于某個阈值(一般操作系統設定為128K,可以修改)時,通過brk/sbrk系統調用,控制堆頂指針向高地址偏移(malloc)或者低地址偏移(free)。
(4)文件映射區:動态内存,當malloc/free申請釋放内存大于128K時,通過mmap系統調用分配一塊虛拟地址空間。
(5)棧:用于存放局部變量和進程上下文。
看到這裡可能會産生一個疑問:既然都有了物理内存,為什麼還要有虛拟内存呢?這是因為由于成本的限制,物理内存往往無法做的很大,但是進程運行階段所需申請的内存可能遠遠超過物理内存,并且系統不可能隻跑一個進程,會有多個進程一起申請使用内存,如果都直接向物理内存進行申請使用肯定無法滿足。通過引入虛拟内存,每個進程都有自己獨立的虛拟地址空間,這個空間理論上可以無限大,因為它并不要錢。一個進程同一時刻不可能所有變量數據都會訪問到,隻需要在訪問某部分數據時,把這一塊虛拟内存映射到物理内存,其他沒有實際訪問過的虛拟地址空間并不會占用到物理内存,這樣對物理内存的消耗就大大減少了 。
系統内核為每個進程都維護了一份從虛拟内存到物理内存的映射表,稱為頁表。頁表根據虛拟地址,查找出鎖映射的物理頁位置和數據在物理頁中的偏移量,便得到了實際需要訪問的物理地址。(具體的多級頁表實現本文不深入探讨)
如下圖所示:
這裡還要提到一個概念,駐留内存,這是指虛拟内存中實際映射到物理内存的那部分,也就是進程實際占用的物理内存大小。所以判斷一個進程使用的内存大小,主要是看占用的物理内存,也就是駐留内存的大小,即RSS。
進程在運行過程中,會加載許多操作系統的動态庫,比如 libc.so、libld.so等。這些庫對于每個進程而言都是公用的,它們在内存中實際隻會加載一份,這部分稱為共享内存。如上圖中的A4和B3部分即為共享内存,實際都映射到同一塊物理内存。
注意,進程占用的共享内存也是計算到駐留内存中的。
另外關于c Linux後台服務器開發的一些知識點分享:Linux,Nginx,MySQL,Redis,P2P,K8S,Docker,TCP/IP,協程,DPDK,webrtc,音視頻等等視頻。
喜歡的朋友可以後台私信【1】獲取學習視頻
,
更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!