1. 程式人生 > >系統技術非業餘研究 » Linux Used記憶體到底哪裡去了?

系統技術非業餘研究 » Linux Used記憶體到底哪裡去了?

前幾天 純上 同學問了一個問題:

我ps aux看到的RSS記憶體只有不到30M,但是free看到記憶體卻已經使用了7,8G了,已經開始swap了,請問ps aux的實際實體記憶體統計是不是漏了哪些記憶體沒算?我有什麼辦法確定free中used的記憶體都去哪兒了呢?

這個問題不止一個同學遇到過了,之前子嘉同學也遇到這個問題,記憶體的計算總是一個迷糊賬。 我們今天來把它算個清楚下!

通常我們是這樣看記憶體的剩餘情況的:

$free -m
             total       used       free     shared    buffers     cached
Mem:         48262       7913      40349          0         14        267
-/+ buffers/cache:       7631      40631
Swap:         2047        336       1711

那麼這個資訊是如何解讀的呢,以下這個圖解釋的挺清楚的!
free

補充(不少人反映圖不清晰,請參考:http://www.redbooks.ibm.com/redpapers/pdfs/redp4285.pdf P46-47)

上面的情況下我們總的記憶體有48262M,用掉了7913M。 其中buffer+cache總共14+267=281M, 由於這種型別的記憶體是可以回收的,雖然我們用掉了7913M,但是實際上我們如果實在需要的話,這部分buffer/cache記憶體是可以放出來的。

我們來演示下:

$ sudo sysctl vm.drop_caches=3
vm.drop_caches = 3
$ free -m
             total       used       free     shared    buffers     cached
Mem:         48262       7676      40586          0          3         41
-/+ buffers/cache:       7631      40631
Swap:         2047        336       1711

我們把buffer/cache大部分都清除乾淨了,只用了44M,所以我們這次used的空間是7676M。
到現在我們比較清楚幾個概念:
1. 總的記憶體多少
2. buffer/cache記憶體可以釋放的。
3. used的記憶體的概率。

即使是這樣我們還是要繼續追查下used的空間(7637M)到底用到哪裡去了?

這裡首先我們來介紹下nmon這個工具,它對記憶體的使用顯示比較直觀。
nmon

使用的記憶體的去向我們很自然的就想到作業系統系統上的各種程序需要消耗各種記憶體,我們透過top工具來看下:
top

通常我們會看程序的RES這一項,這項到底是什麼意思呢?這個數字從哪裡出來的呢? 通過strace對top和nmon的追蹤和結合原始碼,我們確定這個值是從/proc/PID/statm的第二個欄位讀取出來的.
那這個欄位什麼意思呢?
man proc或者http://www.kernel.org/doc/man-pages/online/pages/man5/proc.5.html 會詳細的解釋/proc/下的檔案的具體意思,我們摘抄下:

/proc/[pid]/statm
Provides information about memory usage, measured in pages. The
columns are:

size total program size
(same as VmSize in /proc/[pid]/status)
resident resident set size
(same as VmRSS in /proc/[pid]/status)
share shared pages (from shared mappings)
text text (code)
lib library (unused in Linux 2.6)
data data + stack
dt dirty pages (unused in Linux 2.6)

resident set size 也就是每個程序用了具體的多少頁的記憶體。由於linux系統採用的是虛擬記憶體,程序的程式碼,庫,堆和棧使用的記憶體都會消耗記憶體,但是申請出來的記憶體,只要沒真正touch過,是不算的,因為沒有真正為之分配物理頁面。

我們實際程序使用的物理頁面應該用resident set size來算的,遍歷所有的程序,就可以知道所有的所有的程序使用的記憶體。
我們來實驗下RSS的使用情況:

$ cat RSS.sh
#/bin/bash                                                                                                               
for PROC in `ls  /proc/|grep "^[0-9]"`
do
  if [ -f /proc/$PROC/statm ]; then
      TEP=`cat /proc/$PROC/statm | awk '{print ($2)}'`
      RSS=`expr $RSS + $TEP`
  fi
done
RSS=`expr $RSS \* 4`
echo $RSS"KB"
$ ./RSS.sh  
7024692KB

從數字來看,我們的程序使用了大概7024M記憶體,距離7637M還有幾百M記憶體哪裡去了? 哪裡去了? 貓吃掉了?
我們再回頭來仔細看下nmon的記憶體統計表。

nmon1

那個該死的slab是什麼呢? 那個PageTables又是什麼呢?

簡單的說核心為了高效能每個需要重複使用的物件都會有個池,這個slab池會cache大量常用的物件,所以會消耗大量的記憶體。執行命令:

$ slabtop

我們可以看到:
slabtop
從圖我們可以看出各種物件的大小和數目,遺憾的是沒有告訴我們slab消耗了多少記憶體。
我們自己來算下好了:

$ echo `cat /proc/slabinfo |awk 'BEGIN{sum=0;}{sum=sum+$3*$4;}END{print sum/1024/1024}'` MB
904.256 MB

好吧,把每個物件的數目*大小,再累加,我們就得到了總的記憶體消耗量:904M

那麼PageTables呢? 我們萬能的核心組的同學現身了:

伯瑜:
你還沒有計算page tables的大小,還有struct page也有一定的大小(每個頁一個,64bytes),如果是2.6.32的話,每個頁還有一個page_cgroup(32bytes),也就是說記憶體大小的2.3%(96/4096)會被核心固定使用的
含黛:
struct page是系統boot的時候就會根據記憶體大小算出來分配出去的,18核心是1.56%左右,32核心由於cgroup的原因會在2.3%

好吧,知道是幹嘛的啦,管理這些物理頁面的硬開銷,那麼具體是多少呢?

$ echo `grep PageTables /proc/meminfo | awk '{print $2}'` KB
58052 KB

好吧,小結下!記憶體的去向主要有3個:1. 程序消耗。 2. slab消耗 3.pagetable消耗。
我把三種消耗彙總下和free出的結果比對下,這個指令碼的各種計算項仲同學幫忙搞定的:

$ cat cm.sh
#/bin/bash
for PROC in `ls /proc/|grep "^[0-9]"`
do
  if [ -f /proc/$PROC/statm ]; then
      TEP=`cat /proc/$PROC/statm | awk '{print ($2)}'`
      RSS=`expr $RSS + $TEP`
  fi
done
RSS=`expr $RSS \* 4`
PageTable=`grep PageTables /proc/meminfo | awk '{print $2}'`
SlabInfo=`cat /proc/slabinfo |awk 'BEGIN{sum=0;}{sum=sum+$3*$4;}END{print sum/1024/1024}'`

echo $RSS"KB", $PageTable"KB", $SlabInfo"MB"
printf "rss+pagetable+slabinfo=%sMB\n" `echo $RSS/1024 + $PageTable/1024 + $SlabInfo|bc`
free -m

$ ./cm.sh
7003756KB, 59272KB, 904.334MB
rss+pagetable+slabinfo=7800.334MB
             total       used       free     shared    buffers     cached
Mem:         48262       8050      40211          0         17        404
-/+ buffers/cache:       7629      40633
Swap:         2047        336       1711

free報告說7629M, 我們的cm指令碼報告說7800.3M, 我們的CM多報了171M。
damn,這又怎麼回事呢?

我們重新校對下我們的計算。 我們和nmon來比對下,slab和pagetable的值是吻合的。 那最大的問題可能在程序的消耗計算上。
resident resident set size 包括我們使用的各種庫和so等共享的模組,在前面的計算中我們重複計算了。

$ pmap `pgrep bash`
...
22923:   -bash
0000000000400000    848K r-x--  /bin/bash
00000000006d3000     40K rw---  /bin/bash
00000000006dd000     20K rw---    [ anon ]
00000000008dc000     36K rw---  /bin/bash
00000000013c8000    592K rw---    [ anon ]
000000335c400000    116K r-x--  /lib64/libtinfo.so.5.7
...
0000003ec5220000      4K rw---  /lib64/ld-2.12.so
0000003ec5221000      4K rw---    [ anon ]
0000003ec5800000   1628K r-x--  /lib64/libc-2.12.so
...
0000003ec5b9c000     20K rw---    [ anon ]
00007f331b910000  96836K r----  /usr/lib/locale/locale-archive
00007f33217a1000     48K r-x--  /lib64/libnss_files-2.12.so
...
00007f33219af000     12K rw---    [ anon ]
00007f33219bf000      8K rw---    [ anon ]
00007f33219c1000     28K r--s-  /usr/lib64/gconv/gconv-modules.cache
00007f33219c8000      4K rw---    [ anon ]
00007fff5e553000     84K rw---    [ stack ]
00007fff5e5e4000      4K r-x--    [ anon ]
ffffffffff600000      4K r-x--    [ anon ]
 total           108720K

多出的171M正是共享庫重複計算的部分。
但是由於每個程序共享的東西都不一樣,我們也沒法知道每個程序是如何共享的,沒法做到準確的區分。

所以只能留點小遺憾,歡迎大家來探討。

總結:記憶體方面的概念很多,需要深入挖掘!

祝玩的開心!

Post Footer automatically generated by wp-posturl plugin for wordpress.

相關推薦

系統技術業餘研究 » Linux Used記憶體到底哪裡

前幾天 純上 同學問了一個問題: 我ps aux看到的RSS記憶體只有不到30M,但是free看到記憶體卻已經使用了7,8G了,已經開始swap了,請問ps aux的實際實體記憶體統計是不是漏了哪些記憶體沒算?我有什麼辦法確定free中used的記憶體都去哪兒了呢? 這個問題不止一個同學遇到過了

系統技術業餘研究 » Linux快取記憶體使用率調查

Linux的快取記憶體pagecache對效能的影響至關重要,但是實際系統中我們的利用率如何呢,特別是具體到每個裝置的利用情況。 從下圖我們可以很清楚的看到: 我們知道IO請求由vfs發起,經過pagecache快取,擋不住的就落實到io裝置去,那麼統計這個利用率就很簡單。 我們只要知道擋不住的

系統技術業餘研究 » Linux系統記憶體相關資訊獲取

大型的伺服器,特別是資料庫伺服器的主要瓶頸主要在記憶體,CPU,以及IO上。CPU是可再生資源,不夠用等等就有了;記憶體和土地一樣是不可再生資源,被佔用了,後續的使用必須等到該資源釋放.而IO也非常依賴於記憶體的使用情況,故記憶體的倒騰效率會大大影響伺服器的效率,那麼瞭解伺服器記憶體的使用情況就非

系統技術業餘研究 » Linux下新系統呼叫sync_file_range

我們在做資料庫程式或者IO密集型的程式的時候,通常在更新的時候,比如說資料庫程式,希望更新有一定的安全性,我們會在更新操作結束的時候呼叫fsync或者fdatasync來flush資料到持久裝置去。而且通常是以頁面為單位,16K一次或者4K一次。 安全性保證了,但是效能就有很大的損害。而且我們更新

系統技術業餘研究 » Linux檔案預讀分析以及評估對系統的影響

Linux系統很重要的一個性能提升點就是它的Pagecache, 因為記憶體比IO快太多了,所以大家都想進辦法來利用這個cache。 檔案系統也不例外,為了達到高效能,檔案讀取通常採用預讀來預測使用者的行為,把使用者可能需要的資料預先讀取到cache去,達到高效能的目的。 Linux各個發行版re

系統技術業餘研究 » Linux下方便的socket讀寫檢視器(socktop)

晚上 雕樑 說要找個工具來調查下unix域套接字的傳送和接受情況,比如說A程式是否送出,B程式是否接收到,他找了tcpdump ,wireshark什麼的,貌似都不支援。 這時候還是偉大的systemtap來救助了。 因為所有的socket通訊都是通過socket介面來的,任何family的通訊

系統技術業餘研究 » Linux下誰在消耗我們的cache

Linux下對檔案的訪問和裝置的訪問通常會被cache起來加快訪問速度,這個是系統的預設行為。 而cache需要耗費我們的記憶體,雖然這個記憶體最後可以通過echo 3>/proc/sys/vm/drop_caches這樣的命令來主動釋放。但是有時候我們還是需要理解誰消耗了我們的記憶體。 我

系統技術業餘研究 » Linux下誰在切換我們的程序

我們在做Linux伺服器的時候經常會需要知道誰在做程序切換,什麼原因需要做程序切換。 因為程序切換的代價很高,我給出一個LMbench測試出來的數字: Context switching – times in microseconds – smaller is better ———————————

系統技術業餘研究 » Linux下pstack的實現

Linux下有時候我們需要知道一個程序在做什麼,比如說程式不正常的時候,他到底在幹嗎?最直接的方法就是打印出他所有執行緒的呼叫棧,這樣我們從棧再配合程式程式碼就知道程式在幹嗎了。 Linux下這個工具叫做pstack. 使用方法是 # pstack Usage: pstack <proce

系統技術業餘研究 » Linux下試驗大頁面對映(MAP_HUGETLB)

Linux對大頁面記憶體的引入對減少TLB的失效效果不錯,特別是記憶體大而密集型的程式,比如說在資料庫中的使用。innodb引擎就支援大頁面記憶體,具體使用可參見 這裡。 大頁面更詳細的資料可以參考: Documentation/vm/hugetlbpage.txt 過去使用大頁面記憶體主要透過h

系統技術業餘研究 » Linux 2.6.38 User

Linux核心裡面自帶非常多的加密模組,這是模組經過調優效能非常高, 而且現在又很多硬體本身支援加密功能,比如intel的CPU支援AES加密指令,那些核心的那幫人知道更好如何利用這些硬體更快的完成加密功能的, 他們寫的這些硬體的驅動在drivers/crypto目錄裡. 所以如果我們能在使用者

系統技術業餘研究 » Linux IO協議棧框圖

這張圖很清晰的把linux IO協議棧的層次給勾出來了,而且內容很與時俱進,特別是SCSI裝置的層次對大家理解sg3這樣的包非常有幫助,強烈推薦大家好好研習! 祝玩得開心! Post Footer automatically generated by wp-posturl plugin fo

系統技術業餘研究 » Linux下非同步IO(libaio)的使用以及效能

Linux下非同步IO是比較新的核心裡面才有的,非同步io的好處可以參考這裡. 但是文章中aio_*系列的呼叫是glibc提供的,是glibc用執行緒+阻塞呼叫來模擬的,效能很差,千萬千萬不要用。 我們今天要說的是真正的原生的非同步IO介面. 由於這幾個系統呼叫glibc沒有提供相應的封裝,所以l

系統技術業餘研究 » Linux下Fio和Blktrace模擬塊裝置的訪問模式

我們在做塊裝置調優的時候, 我們關心的是塊裝置是如何被訪問的,也就是訪問模式(比如說每次從什麼地方讀,每次讀多少塊,熱點在哪裡等),至於每次讀寫的什麼資料我們並不關心. 這些模式當然可以自己去構造,但是如果能把真實應用的訪問模式記錄下來,並且在調優的時候能重放,我們就可以一遍又一遍的除錯直到達到最

系統技術業餘研究 » Linux TASK_IO_ACCOUNTING功能以及如何使用

在過去我們瞭解系統IO的情況大多數是通過iostat來獲取的,這個粒度只能精確到每個裝置。通常我們會想了解每個程序,執行緒層面發起了多少IO,在Linux 2.6.20之前除了用systemtap這樣的工具來實現是沒有其他方法的,因為系統沒有暴露這方面的統計。 disktop per裝置per應用

系統技術業餘研究 » Linux下方便的塊裝置檢視工具lsblk

之前在Linux下看有什麼塊裝置,通常都用fdisk什麼的或者直接ls /dev/ 人肉去看看, 很土,不方便。 前二天在江楓的網站上看到了介紹的lsblk,這玩意不錯,推薦給大家。 這個工具屬於util-linux-ng包,在RHEL 6.1上是安裝好的啦,直接用就好。 ubuntu高版本下也有

系統技術業餘研究 » Linux下pipe使用注意事項

Linux下的pipe使用非常廣泛, shell本身就大量用pipe來粘合生產者和消費者的. 我們的伺服器程式通常會用pipe來做執行緒間的ipc通訊. 由於unix下的任何東西都是檔案,只要是檔案,在讀取的時候,,就會設定last access time, 所以pipe也不例外., 但是這個時間

系統技術業餘研究 » 網路棧記憶體不足引發程序掛起問題

我們知道TCP socket有傳送緩衝區和接收緩衝區,這二個緩衝區都可以透過setsockopt設定SO_SNDBUF,SO_RCVBUF來修改,但是這些值設多大呢?這些值和協議棧的記憶體控制相關的值什麼關係呢? 我們來解釋下: $ sysctl net|grep mem net.core.wme

系統技術業餘研究 » Linux常用效能調優工具索引

霸爺您好,麻煩請教個問題,我們最近一個專案上有個奇怪的問題,基於實時linux系統,兩個實時執行緒通過mq_send傳送訊息,A發訊息給B,是非阻塞的訊息佇列,A傳送訊息B進行處理,A傳送訊息後發現mq_send的開銷與B對該訊息的處理時延相關,也就是說B處理的快,那麼A呼叫的mq_send返回

系統技術業餘研究 » Linux下如何知道檔案被那個程序寫

晚上朔海同學問: 一個檔案正在被程序寫 我想檢視這個程序 檔案一直在增大 找不到誰在寫 使用lsof也沒找到 這個問題挺有普遍性的,解決方法應該很多,這裡我給大家提個比較直觀的方法。 linux下每個檔案都會在某個塊裝置上存放,當然也都有相應的inode, 那麼透過vfs.write我們就可以知道