程序在Linux上實際需要多少記憶體
你經常會在基於Linux的系統上面臨的問題之一是管理記憶體預算。如果程式使用的記憶體多於可用記憶體,則可能會發生交換,這常常會對效能造成嚴重影響,或者激活了記憶體溢位(OOM),從而完全殺死了程序。
在調整記憶體使用之前,通過配置優化或者負載管理,有助於瞭解給定程式實際使用多少記憶體。
如果你的系統本質上執行單使用者程式(總是有很多系統程序),那麼這很容易。例如,如果我在具有128GB RAM的系統上執行專用的MySQL伺服器,則可以使用“ used”作為已使用記憶體的標識,並使用“ available”作為仍可以使用的記憶體。
root@rocky:/mnt/data2/mysql# free -h total used free shared buff/cache available Mem: 125Gi 88Gi 5.2Gi 2.0Mi 32Gi 36Gi Swap: 63Gi 33Mi 63Gi
對於交換(swap),如果系統交換不頻繁,即使使用了交換空間,它通常也會保留“不需要的垃圾”,這不需要考慮計算。
如果你使用的是Percona的監控和管理工具(PMM),則會在“Memory Utilization”中看到它:
並在“node summary”面板的的“swap activity”圖中:
如果執行的多個程序共享著資源,則事情會變得複雜,因為“used”記憶體和程序之間沒有一一對應的對映。
讓我們只列出其中的一些複雜性:
·fork程序時的copy-on-write語義:所有的程序共享“used”部分的記憶體,直到程序修改本身修改資料,這時候程序有自己的記憶體拷貝
·共享記憶體:顧名思義,共享記憶體就是不同程序間共享的記憶體
·共享庫:庫被對映到每個使用它的程序,是程序使用的記憶體的一部分,儘管在程序間是共享相同的庫
·記憶體對映檔案和匿名mmap():這裡有很多更復雜的細節。例如,檢視“記憶體對映檔案”以獲取更多詳細資訊。
考慮到這種複雜性,讓我們看一下“top”輸出,這是檢視Linux當前負載的最常用程式之一。預設情況下,"top"按CPU使用率對程序進行排序,因此我們將按“ Shift-M”將其按(駐留)記憶體使用率進行排序。
首先你會注意到的是,該系統只有1GB的實體記憶體,並且具有多個程序,這些程序的虛擬記憶體(VIRT)超過1GB。
由於各種原因,現代記憶體分配器和程式語言(如GoLang)可以分配很多它們實際上沒有使用的虛擬記憶體,因此虛擬記憶體的使用對於瞭解一個程序需要多少實際記憶體沒有什麼價值。
現在有常駐記憶體(RES),它向我們顯示了該程序實際使用了多少實體記憶體。這很好...但是有問題。記憶體可以是非駐留記憶體,這是因為它不是真正的“used”並且僅作為虛擬記憶體存在,或者是因為它已被換出。
如果我們檢視統計核心實際為該程序提供的內容,就會發現有更多可用資料:
root@PMM2Server:~# cat /proc/3767/status Name: prometheus Umask: 0022 State: S (sleeping) Tgid: 3767 Ngid: 0 Pid: 3767 PPid: 3698 TracerPid: 0 Uid: 1000 1000 1000 1000 Gid: 1000 1000 1000 1000 FDSize: 256 Groups: 1000 NStgid: 3767 17 NSpid: 3767 17 NSpgid: 3767 17 NSsid: 3698 1 VmPeak: 3111416 kB VmSize: 3111416 kB VmLck: 0 kB VmPin: 0 kB VmHWM: 608596 kB VmRSS: 291356 kB RssAnon: 287336 kB RssFile: 4020 kB RssShmem: 0 kB VmData: 1759440 kB VmStk: 132 kB VmExe: 26112 kB VmLib: 8 kB VmPTE: 3884 kB VmSwap: 743116 kB HugetlbPages: 0 kB CoreDumping: 0 Threads: 11 SigQ: 0/3695 SigPnd: 0000000000000000 ShdPnd: 0000000000000000 SigBlk: fffffffe3bfa3a00 SigIgn: 0000000000000000 SigCgt: fffffffe7fc1feff CapInh: 00000000a80425fb CapPrm: 0000000000000000 CapEff: 0000000000000000 CapBnd: 00000000a80425fb CapAmb: 0000000000000000 NoNewPrivs: 0 Seccomp: 2 Speculation_Store_Bypass: vulnerable Cpus_allowed: 1 Cpus_allowed_list: 0 Mems_allowed: 00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000000,00000001 Mems_allowed_list: 0 voluntary_ctxt_switches: 346 nonvoluntary_ctxt_switches: 545
VmSwap是一個特別有趣的資料點,因為它顯示了該程序使用的交換出的記憶體量。
VmRSS + VmSwap可以更好地指示程序所需的“物理”記憶體。在上面的例子中,它是1010MB,比常駐集284MB高很多,但比3038MB的“虛擬記憶體”大小小很多。
換出部分的問題,儘管我們不知道它是否被永久替換掉。例如,某些程式碼或資料在你的程式中沒有用到,或者由於記憶體壓力被換出。我們確實需要將其放在實際記憶體(RAM)中以實現最佳效能-但我們沒有足夠的可用記憶體。
在本例子中,要檢視的有用的資料點是主要頁面錯誤(major page faults)。它不在輸出的內容中,但是可以從另一個檔案中看:/proc/[pid]/stat。這裡是stack overflow上的一些有用的資訊(https://stackoverflow.com/questions/39066998/what-are-the-meaning-of-values-at-proc-pid-stat)。
主要頁面錯誤(major page faults)數量多表示程式主要需要的不在實體記憶體中。這樣就會包含交換活動,還包括對當前不在RAM中,共享庫中當前未對映的程式碼的引用、或對記憶體對映檔案中的資料的引用。無論如何,主要頁面錯誤(major page faults)高發生率通常表明RAM壓力大。
不過,讓我們轉到“top”的輸出結果,看看是否可以在其中顯示更多有用的資訊。您可以使用“ F”鍵盤快捷鍵來選擇要顯示的欄位。
你可以新增SWAP,Major Faults Delta和used列來顯示我們在上面的談論的所有內容!
觀看這張圖片,我們可以看到很大一部分“ prometheus”程序被換出了,並且每秒發生2K個主要頁面錯誤。
“ clickhouse-serv”程序是另一個有趣的示例,因為它具有超過4G的“resident size”,但使用的記憶體相對較少,而主要頁面錯誤也較少。
最後,讓我們看一下“ percona-qan-api”程序,該程序只交換了很小的一部分,但也顯示了2K的主要頁面錯誤。老實說,我不太確定它是什麼,但似乎與swap-IO沒有關係。
最後
是否想檢視程序正在使用多少記憶體? 不要檢視虛擬記憶體大小或常駐記憶體大小,而是檢視定義為常駐記憶體大小+交換使用情況的“used”記憶體。
想看看是否有實際的記憶體壓力?針對你要調查的程序,檢視系統級別(system-wide)的交換輸入/輸出統計資訊以及主要頁面錯誤(major page faults)。
原文:https://www.percona.com/blog/2020/09/11/how-much-memory-does-the-process-really-take-on-linux/