正確確定Linux中的記憶體使用情況

正確確定Linux中的記憶體使用情況

我對看到的一些結果有點困惑附註自由的

在我的伺服器上,這是結果free -m

[root@server ~]# free -m
             total       used       free     shared    buffers     cached
Mem:          2048       2033         14          0         73       1398
-/+ buffers/cache:        561       1486
Swap:         2047         11       2036

我對Linux如何管理記憶體的理解是,它將磁碟使用情況儲存在RAM中,以便後續的每次存取更快。我相信這是由“快取”列指示的。此外,各種緩衝區儲存在 RAM 中,如「緩衝區」列中所示。

因此,如果我理解正確,「實際」使用量應該是「-/+ buffers/cache」的「已使用」值,在本例中為 561。

因此,假設所有這些都是正確的,那麼讓我困惑的部分是ps aux.

我對ps結果的理解是,第六列 (RSS) 代表進程使用的記憶體大小(以千位元組為單位)。

所以當我運行這個命令時:

[root@server ~]# ps aux | awk '{sum+=$6} END {print sum / 1024}'
1475.52

結果不應該是“-/+ buffers/cache”的“used”欄位嗎free -m

那麼,如何正確判斷Linux中進程的記憶體使用情況呢?顯然我的邏輯有問題。

答案1

無恥地複製/貼上我的答案伺服器故障就在前幾天:-)

Linux 虛擬記憶體系統就沒那麼簡單。您不能僅將所有 RSS 欄位相加並取得 報告的usedfree。造成這種情況的原因有很多,但我將列出幾個最重要的原因。

  • 當進程分叉時,父進程和子進程都會顯示相同的 RSS。然而,Linux 採用寫入時複製,因此兩個進程實際上使用相同的記憶體。只有當其中一個進程修改了記憶體時,它才會真正被複製。
    這將導致該free數字小於topRSS 總和。

  • RSS 值不包含共享記憶體。由於共享記憶體不屬於任何一個進程,因此top不將其包含在 RSS 中。
    這將導致該free數字大於topRSS 總和。

這些數字可能無法相加還有許多其他原因。這個答案只是想表明記憶體管理非常複雜,您不能僅添加/減去單一值來獲得總記憶體使用量。

答案2

如果您正在尋找加起來的記憶體數字,請查看斯梅姆

smem 是一個可以提供有關 Linux 系統記憶體使用情況的大量報告的工具。與現有工具不同,smem 可以報告比例集大小 (PSS),這是虛擬記憶體系統中庫和應用程式使用的記憶體量的更有意義的表示。

由於大部分實體記憶體通常在多個應用程式之間共享,因此稱為駐留集大小 (RSS) 的記憶體使用量標準度量將顯著高估記憶體使用量。相反,PSS 會測量每個應用程式對每個共享區域的“公平份額”,以給出切合實際的測量結果。

例如這裡:

# smem -t
  PID User     Command                         Swap      USS      PSS      RSS
...
10593 root     /usr/lib/chromium-browser/c        0    22868    26439    49364 
11500 root     /usr/lib/chromium-browser/c        0    22612    26486    49732 
10474 browser  /usr/lib/chromium-browser/c        0    39232    43806    61560 
 7777 user     /usr/lib/thunderbird/thunde        0    89652    91118   102756 
-------------------------------------------------------------------------------
  118 4                                       40364   594228   653873  1153092 

這裡有趣的專欄也是如此PSS,因為它考慮了共享記憶體。
不像RSS將其相加才有意義。我們在這裡獲得了用戶態進程總共 654Mb 的空間。

系統範圍的輸出告訴我們剩下的:

# smem -tw
Area                           Used      Cache   Noncache 
firmware/hardware                 0          0          0 
kernel image                      0          0          0 
kernel dynamic memory        345784     297092      48692 
userspace memory             654056     181076     472980 
free memory                   15828      15828          0 
----------------------------------------------------------
                            1015668     493996     521672 

因此 1Gb RAM 總計= 654Mb用戶態進程+ 346Mb核心記憶體+ 16Mb可用空間
(給予或減少幾 Mb)

總體而言,大約一半的記憶體用於快取 (494Mb)。

獎金問題:這裡的用戶態快取與核心快取是什麼?


順便說一句,對於一些視覺嘗試:

# smem  --pie=name

在此輸入影像描述

答案3

一個非常好的工具是pmap列出某個進程的當前記憶體使用情況:

pmap -d PID

有關它的更多信息,請參閱手冊頁man pmap並查看每個系統管理員都應該知道的 20 個 Linux 系統監控工具,其中列出了我經常用來獲取有關我的 Linux 機器的資訊的優秀工具。

答案4

正如其他人正確指出的那樣,很難掌握進程使用的實際記憶體、共享區域、映射檔案等。

如果您是實驗者,您可以運行瓦爾格林德和地塊。對於普通用戶來說,這可能有點繁重,但隨著時間的推移,您將了解應用程式的記憶體行為。如果應用程式 malloc() 正是它所需要的,那麼這將為您提供進程的真實動態記憶體使用情況的良好表示。但這個實驗可能會「中毒」。

讓事情變得複雜的是,Linux 允許您過度使用你的記憶。當您 malloc() 記憶體時,您就表明了消耗記憶體的意圖。但是,直到您將一個位元組寫入分配的“RAM”的新頁面後,分配才真正發生。您可以透過編寫並執行一個小 C 程式來向自己證明這一點,如下所示:

// test.c
#include <malloc.h>
#include <stdio.h>
#include <unistd.h>
int main() {
    void *p;
    sleep(5)
    p = malloc(16ULL*1024*1024*1024);
    printf("p = %p\n", p);
    sleep(30);
    return 0;
}

# Shell:
cc test.c -o test && ./test &
top -p $!

在 RAM 小於 16GB 的電腦上運行此程序,瞧! (不,不是真的)。

請注意,top您看到“VIRT”為 16.004G,但 %MEM 為 0.0

使用 valgrind 再次運行:

# Shell:
valgrind --tool=massif ./test &
sleep 36
ms_print massif.out.$! | head -n 30

Massif 說「所有 allocs() 的總和 = 16GB」。所以這不是很有趣。

但是,如果你在理智的過程:

# Shell:
rm test test.o
valgrind --tool=massif cc test.c -o test &
sleep 3
ms_print massif.out.$! | head -n 30

--------------------------------------------------------------------------------
Command:            cc test.c -o test
Massif arguments:   (none)
ms_print arguments: massif.out.23988
--------------------------------------------------------------------------------


    KB
77.33^                                                                       :
     |                                                                      #:
     |                                                                :@::@:#:
     |                                                           :::::@@::@:#:
     |                                                         @:: :::@@::@:#:
     |                                                     ::::@:: :::@@::@:#:
     |                                             ::@:::@:::::@:: :::@@::@:#:
     |                                            @::@:::@:::::@:: :::@@::@:#:
     |                                            @::@:::@:::::@:: :::@@::@:#:
     |                      :@@@@@@@@@@@@@@@@@@@@:@::@:::@:::::@:: :::@@::@:#:
     |                      :@@                  :@::@:::@:::::@:: :::@@::@:#:
     |                    :@:@@                  :@::@:::@:::::@:: :::@@::@:#:
     |                    :@:@@                  :@::@:::@:::::@:: :::@@::@:#:
     |                   :@@:@@                  :@::@:::@:::::@:: :::@@::@:#:
     |                   :@@:@@                  :@::@:::@:::::@:: :::@@::@:#:
     |              :@::::@@:@@                  :@::@:::@:::::@:: :::@@::@:#:
     |          :::::@::::@@:@@                  :@::@:::@:::::@:: :::@@::@:#:
     |        :::::::@::::@@:@@                  :@::@:::@:::::@:: :::@@::@:#:
     |       ::::::::@::::@@:@@                  :@::@:::@:::::@:: :::@@::@:#:
     |       ::::::::@::::@@:@@                  :@::@:::@:::::@:: :::@@::@:#:
   0 +----------------------------------------------------------------------->Mi
     0                                                                   1.140

在這裡我們看到(非常憑經驗並且非常有信心)編譯器分配了 77KB 堆。

為什麼要如此努力地取得堆使用情況?因為進程使用的所有共享物件和文字部分(在本例中為編譯器)都不是很有趣。它們是流程的持續開銷。事實上,該過程的後續調用幾乎是「免費」的。

另外,比較和對比以下內容:

MMAP() 一個 1GB 檔。您的 VMSize 將為 1+GB。但是您的駐留集大小將只是您導致分頁的文件部分(透過取消引用指向該區域的指標)。如果您「讀取」整個文件,那麼當您讀到末尾時,內核可能已經調出開頭部分(這很容易做到,因為內核確切地知道如果再次取消引用,如何/在哪裡替換這些頁面)。無論哪種情況,VMSize 和 RSS 都不能很好地指示記憶體「使用情況」。您實際上還沒有 malloc() 任何東西。

相比之下,Malloc() 會佔用大量記憶體——直到記憶體交換到磁碟。所以你分配的記憶體現在超過了你的 RSS。在這裡,您的 VMSize 可能會開始告訴您一些資訊(您的進程擁有的記憶體比 RAM 中實際駐留的記憶體多)。但仍很難區分共享頁面的虛擬機器和交換資料的虛擬機器。

這就是 valgrind/massif 有趣的地方。它顯示你擁有什麼故意地已指派(無論頁面的狀態如何)。

相關內容