共計 2826 個字符,預計需要花費 8 分鐘才能閱讀完成。
本文丸趣 TV 小編為大家詳細介紹“Linux 內存的分配和釋放是什么”,內容詳細,步驟清晰,細節處理妥當,希望這篇“Linux 內存的分配和釋放是什么”文章能幫助大家解決疑惑,下面跟著丸趣 TV 小編的思路慢慢深入,一起來學習新知識吧。
了解內存分配機制(共享映射與請求分頁)
通過 pmap 命令,可以獲取用戶進程邏輯地址空間中映射的內存信息:
pmap -x $pid
其中 -x 表示獲取詳細信息。
下面是一個例子:
pmap -x $(pidof emacs) |head -20
其中,“Address(地址)”指的進程的邏輯地址空間。
“Kbytes”列表示的是對應邏輯地址的容量,以 Kb 為單位
“RSS”列表示的是實際使用的物理內存容量,由于分頁機制的存在,這個值一般要比”Kbytes”的值要少。
“Mapping”列為邏輯內存的映射方式,其中”[annon]“表示通過 malloc 函數來分配的堆空間(匿名內存),”[stack]“為進程的??臻g,這兩種映射都是將物理內存映射到進程的邏輯內存上去。而”emacs-25.3 Prime;,”libpixbufloader-svg.so”等文件名則表示它們執行的是文件映射,他們對應的是磁盤上的文件。當這些文件被讀入高速緩存后,相應的內存空間被映射成進程的邏輯內存。
當出現多個程序共同使用相同的文件映射 (共享庫) 時,它們可以共享磁盤高速緩存中的同一空間,從而節省物理內存的使用量,這種技術就是”共享映射”技術。
除了共享庫外,進程的 fork 也使用了共享映射技術。當父進程 fork 子進程時,Linux 內核并不對內存中的內容進行實際上的復制,而是將映射到父進程邏輯地址空間內的那部分內容原封不動地共享映射到子進程的邏輯地址空間內。但為了防止父進程和子進程的內存操作相互影響,Linux 內核在進行共享映射時,相應的內存區域會暫時設置為寫保護。當某一方進程試圖操作內存時,會引發只讀異常。內核檢測到這個異常后,會復制操作的這個內存頁,從而使兩個進程都可進行獨立寫入。這種在寫入時復制的機制叫做“寫時復制(copy-on-write)”
另一方面,進程將可執行文件或共享庫文件內容讀入內存并映射到進程邏輯地址空間上時,并不會讀入全部的文件內容,而是先標記”該文件的內容已經被映射到邏輯地址空間內”. 當進程訪問邏輯地址空間時,由于不存在對應的物理內存,會引發換頁錯誤的異常。內容檢測到該異常后會將所需部分以內存頁為單位讀入內存中。這種只讀入所需內容的機制,叫做請求分頁。
了解內存釋放機制
當其他進程需要新的物理內存時,就涉及到如何將尚有數據殘余的物理內存釋放或換出來的問題了。
當需要新物理內存時,會優先釋放 Inactive(file)和 Active(file)中記錄的內存頁,只需要將臟數據寫入文件中再釋放內存頁即可。
而 Inactive(anon)和 Active(anon)內存頁則需要將內容交換到物理磁盤上的 swap 中后再釋放。具體來說,Linux 會在進程頁表上做一個標記,標記出換出內存所對應的邏輯地址。當進程訪問該邏輯地址時,會產生相應物理內存不存在的異常,Linux 內核檢測到這個異常后,會再次將數據從 swap 中加載入空閑內存,并重新配置頁表信息。
Linux 內核使用兩種機制來加快換出處理速度:
一種是預讀。
當某一個內存頁需要換入時,Linux 內核會將其后的幾個內存頁一起換入。因為進程連續訪問多個內存頁的可能性很大。預讀的頁數為內核參數 vm.page-cluster 決定為 2^vm.page-cluster.
另一種是交換緩存。
即在換入某個內存頁后,物理磁盤上交換空間中仍然保留原數據,這種狀態的內存會記錄在“交換緩存”的列表上。這樣當需要再次換出記錄在“交換緩存”上的內存頁的數據時,就無需再次換入了。
每個進程的內存使用情況可以通過查看 /proc/ 進程 ID/status 來查看
cat /proc/$(pidof emacs)/status
Name: emacs Umask: 0022 State: S (sleeping) Tgid: 6769 Ngid: 0 Pid: 6769 PPid: 1 TracerPid: 0 Uid: 1000 1000 1000 1000 Gid: 1000 1000 1000 1000 FDSize: 64 Groups: 986 998 1000 NStgid: 6769 NSpid: 6769 NSpgid: 6769 NSsid: 6769 VmPeak: 567040 kB VmSize: 567040 kB VmLck: 0 kB VmPin: 0 kB VmHWM: 241176 kB VmRSS: 241176 kB RssAnon: 204544 kB RssFile: 36604 kB RssShmem: 28 kB VmData: 231712 kB VmStk: 1596 kB VmExe: 2332 kB VmLib: 47832 kB VmPTE: 1008 kB VmSwap: 0 kB HugetlbPages: 0 kB CoreDumping: 0 Threads: 4 SigQ: 1/15456 SigPnd: 0000000000000000 ShdPnd: 0000000000000000 SigBlk: 0000000000000000 SigIgn: 0000000004381000 SigCgt: 00000001db816eff CapInh: 0000000000000000 CapPrm: 0000000000000000 CapEff: 0000000000000000 CapBnd: 0000003fffffffff CapAmb: 0000000000000000 NoNewPrivs: 0 Seccomp: 0 Cpus_allowed: 3 Cpus_allowed_list: 0-1 Mems_allowed: 1 Mems_allowed_list: 0 voluntary_ctxt_switches: 12951 nonvoluntary_ctxt_switches: 21641
其中比較有用的項有:
VmData
data 段的大小
VmExe
text 段的大小
VmHWM
當前物理內存使用量的 *** 值
WmLck
用 mlock 鎖定的內存大小
VmLib
共享庫的使用量
VmPTE
頁面表的大小
VmPeak
當前物理內存的 *** 值
VmRSS
物理內存的實際使用量
VmSize
邏輯地址的大小
VmStk
堆棧的大小
VmSwap
交換空間的使用量
讀到這里,這篇“Linux 內存的分配和釋放是什么”文章已經介紹完畢,想要掌握這篇文章的知識點還需要大家自己動手實踐使用過才能領會,如果想了解更多相關內容的文章,歡迎關注丸趣 TV 行業資訊頻道。