內存的管理
在內存管理上份爲兩層,一個是線性區,類似於 00c73000-00c88000,對應於虛擬內存,它實際上不佔用實際物理內存;另外一個是具體的物理頁面,它對應我們機器上的物理內存。
這裏要提到一個很重要的概念,內存的延遲分配/按需分配。Linux 內核在用戶申請內存的時候,只是給它分配了一個線性區(也就是虛存),並沒有分配實際物理內存;只有當用戶使用這塊內存的時候(比如malloc後,memset一個字節),內核纔會分配具體的物理頁面給用戶,這時候才佔用寶貴的物理內存。內核釋放物理頁面是通過釋放線性區,找到其所對應 的物理頁面,將其全部釋放的過程。
1.物理內存:
實際內存,常見的有8G 16G 32G 64G等
2.虛擬內存:
操作系統(windows或者linux)基於物理內存有限及內存操作效率考慮,設計了虛擬地址訪問機制,能夠分配比系統現有物理內存更多的內存。虛擬內存使用的是硬盤的空間,硬盤空間動輒幾十G上百G,運用了虛擬內存技術,即拿出一部分硬盤空間來充當內存使用,大幅提升了“可用” 內存的大小。(實際上,CPU還是讀取物理內存)。
Linux下兩種主要Cache方式:Buffer Cache和Page Cache.前者Buffer Cache針對磁盤塊的讀寫,後者Page Cache針對文件等的讀寫。這些Cache有效縮短了I/O系統調用(比如 read,write,getdents)的時間
兩個關鍵概念:
2.1頁面調度
頁面調度是指從磁盤向內存傳輸數據,以及相反的過程,這個過程之所以被稱爲頁面調度,是因爲Linux內存被平均劃分成大小相等的頁面;通常頁面大小爲 4KB和8KB(在Solaris中可以用pagesize命令查看)。當可執行程序開始運行時,它的映象會一頁一頁地從磁盤中讀入,與此類似,當某些內存在一段時間內空閒(不被使用),就可以把它們換出到交換空間中,這樣就可以把空閒的RAM交給其他需要它的程序使用。
2.2交換
交換的概念容易和頁面調度通混淆,頁面調度是指把一個進程所佔內存的空閒部分傳輸到磁盤上,而交換是指當系統中實際的內存已不夠滿足新的分配需求時,把整個進程傳輸到磁盤上,交換活動通常意味着內存不足。其中,交換空間是專門用於臨時存儲內存的一塊磁盤空間,通常在頁面調度和交換進程數據時使用。(linux下可配置 /proc/sys/vm/swappiness ,默認爲10,也就是達到90,既可以使用swap。看睡眠情況,一般不睡眠情況下,32G物理內存以上,則推薦爲8G的交換空間)
程序操作內存
系統函數brk mmap等實現的是直接操作內存,brk是通過移動最新的偏移地址得到內存(這個會存在內存空洞),而mmap是找空閒內存,而glic(ptmalloc)等運行庫爲了內存高效,會進行封裝:其多個小128k的內存申請釋放後,進行內存合併管理;大於128,用mmap進行直接操作內存,沒有合併管理一說。
因此,可能存在代碼free,但是虛擬內存還是佔用的。
對內存空洞要求高的話,建議使用tcmalloc。
內存查看
1.top命令
【大致看下,容易有歧義,建議以free來查看內存情況】
【按(shift+M)會進行內存排序,關注下VIRT和res不要一直漲就可以了】
2.free
[root@scs-2 tmp]# free
total used free shared buffers cached
Mem: 128 119 8 0 2 22 從OS的角度來看
-/+ buffers/cache: 95 32 應用程序的內存
swap: 255 0 255
第2行-/+ buffers/cache:
-buffers/cache 的內存數: 95 (應用程序的內存,等於第1行的 used - buffers - cached)
+buffers/cache 的內存數: 32 (應用程序的內存,等於第1行的 free + buffers + cached)
可見-buffers/cache反映的是被程序實實在在喫掉的內存,而+buffers/cache反映的是可以挪用的內存總數。
第三行數據是交換分區SWAP的,也就是我們通常所說的虛擬內存。
(mem)行是從OS的角度來看,因爲對於OS,buffers/cached 都是屬於被使用。
used 119 已用內存中包括內核(OS)使用+Application(X, oracle,等)使用的+buffers+cached.
3.一個進程的內存
我們通過free命令查看機器空閒內存時,會發現free的值很小。這主要是因爲,在Linux系統中有這麼一種思想,內存不用白不用,因此它儘可能的cache和buffer一些數據,以方便下次使用。但實際上這些內存也是可以立刻拿來使用的。
所以 空閒內存=free+buffers+cached=total-used
內存泄漏
1.依據
查看一個進程使用的內存,是一個很令人困惑的事情。因爲我們寫的程序,必然要用到動態鏈接庫,將其加入到自己的地址空間中,但是 / proc/pid/statm 統計出來的數據,會將這些動態鏈接庫所佔用的內存也簡單的算進來。
這樣帶來的問題,動態鏈接庫佔用的內存有些是其他程序使用時佔用的,卻算在了你這裏。你的程序中包含了子進程,那麼有些動態鏈接庫重用的內存會被重複計算。
懷疑某處發生了內存泄露,可以查看該進程的maps表,看進程的堆段或者mmap段的虛擬地址空間是否持續增加,如果是,說明很可能發生了內存泄露,如果mmap段虛擬地址空間持續增加,還可以看到各個段的虛擬地址空間的大小,從而可以確定是申請了多大的內存,對調試內存泄露類問題可以起到很好的定位作用。Rss-Resident Set Size 實際使用物理內存(包含共享庫佔用的內存)
學習鏈接
https://www.jianshu.com/p/38a4bcf564d5 內存機制,包括示例內存釋放
https://www.cnblogs.com/yangykaifa/p/7397497.html mtrace 定位泄漏
https://testerhome.com/articles/20547 gdb定位泄漏