當前位置:
首頁 > 知識 > Linux 內存的分配和釋放

Linux 內存的分配和釋放

(點擊

上方公眾號

,可快速關注)




來源:暗無天日,


lujun9972.github.io/blog/2018/04/18/linux內存的分配和釋放/




了解內存分配機制(共享映射與請求分頁)



通過 pmap 命令,可以獲取用戶進程邏輯地址空間中映射的內存信息:





pmap -x $pid




其中 -x 表示獲取詳細信息。




下面是一個例子:




pmap -x $(pidof emacs) |head -20




其中,「Address(地址)」指的進程的邏輯地址空間。




「Kbytes」列表示的是對應邏輯地址的容量,以Kb為單位




「RSS」列表示的是實際使用的物理內存容量,由於分頁機制的存在,這個值一般要比」Kbytes」的值要少。



「Mapping」列為邏輯內存的映射方式,其中」[annon]「表示通過malloc函數來分配的堆空間(匿名內存),」[stack]「為進程的棧空間,這兩種映射都是將物理內存映射到進程的邏輯內存上去。 而」emacs-25.3″,」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


交換空間的使用量




看完本文有收穫?請轉發分享給更多人


關注「ImportNew」,提升Java技能


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 ImportNew 的精彩文章:

通向架構師的道路(第二十六天)漫談架構與設計文檔的寫作技巧
使用 anacron 定期執行任務

TAG:ImportNew |