首先説説虛擬內存和物理內存:

虛擬內存就是採用硬盤來對物理內存進行擴展,將暫時不用的內存頁寫到硬盤上而騰出更多的物理內存讓有需要的進程來用。當這些內存頁需要用的時候在從硬盤讀回內存。這一切對於用户來説是透明的。通常在Linux系統説,虛擬內存就是swap分區。在X86系統上虛擬內存被分為大小為4K的頁。

每一個進程啓動時都會向系統申請虛擬內存(VSZ),內核同意或者拒就請求。當程序真正用到內存時,系統就它映射到物理內存。RSS表示程序所佔的物理內存的大小。用ps命令我們可以看到進程佔用的VSZ和RSS。

# ps –aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
daemon 2177 0.0 0.2 3352 648 ? Ss 23:03 0:00 /usr/sbin/atd
dbus 2196 0.0 0.5 13180 1320 ? Ssl 23:03 0:00 dbus-daemon-1 --sys
root 2210 0.0 0.4 2740 1044 ? Ss 23:03 0:00 cups-config-daemon
root 2221 0.3 1.5 6108 4036 ? Ss 23:03 0:02 hald
root 2231 0.0 0.1 2464 408 tty1 Ss+ 23:03 0:00 /sbin/mingetty tty1

內核會定期將內存中的數據同步到硬盤,這個過程叫做Memory Paging。同時內核也要負責回收不用的內存,將他們分給其他需要的進程。PFRA算法(Page Frame reclaim algorithm)負責回收空閒的內存。算法根據內存頁的類型來決定要釋放的內存頁。有下列4種類型:

1.Unreclaimable –鎖定的,內核保留的頁面;

2.Swappable –匿名的內存頁;

3.Syncable –通過硬盤文件備份的內存頁;

4.Discardable –靜態頁和被丟棄的頁。

 

除了第一種(Unreclaimable)之外其餘的都可以被PFRA進行回收。與之相關的進程是kswapd。在kswapd中,有2個閥值,pages_hige和pages_low。當空閒內存頁的數量低於pages_low的時候,kswapd進程就會掃描內存並且每次釋放出32個free pages,直到free page的數量到達pages_high。具體kswapd是如何回收內存的呢?有如下原則:

1.如果頁未經更改就將該頁放入空閒隊列;

2.如果頁已經更改並且是可備份迴文件系統的,就理解將內存頁的內容寫回磁盤;

3.如果頁已經更改但是沒有任何磁盤上的備份,就將其寫入swap分區。

# ps -ef | grep kswapd
root 30 1 0 23:01 ? 00:00:00 [kswapd0]

在回收內存過程中還有兩個重要的方法,一是LMR(Low on memory reclaiming),另一個是OMK(Out of Memory Killer)。當分配內存失敗的時候LMR將會其作用,失敗的原因是kswapd不能提供足夠的空閒內存,這個時候LMR會每次釋放1024個垃圾頁知道內存分配成功。當LMR不能快速釋放內存的時候,OMK就開始其作用,OMK會採用一個選擇算法來決定殺死某些進程。當選定進程時,就會發送信號SIGKILL,這就會使內存立即被釋放。OMK選擇進程的方法如下:

1.進程佔用大量的內存;

2.進程只會損失少量工作

3.進程具有低的靜態優先級;

4.進程不屬於root用户。

 

進程管理中另一個程序pdflush用於將內存中的內容和文件系統進行同步,比如説,當一個文件在內存中進行修改,pdflush負責將它寫回硬盤。

# ps -ef | grep pdflush
root 28 3 0 23:01 ? 00:00:00 [pdflush]
root 29 3 0 23:01 ? 00:00:00 [pdflush]

每當內存中的垃圾頁(dirty page)超過10%的時候,pdflush就會將這些頁面備份回硬盤。這個比率是可以調節的,通過參數vm.dirty_background_ratio。

# sysctl -n vm.dirty_background_ratio
10

 

Pdflush同PFRA是獨立運行的,當內核調用LMR時,LMR就觸發pdflush將垃圾頁寫回硬盤。

我們來看內存監控的一個例子,用vmstat命令的輸出如下:

# vmstat 3
procs          memory            swap     io        system      cpu
r b  swpd   free   buff cache   si so    bi   bo    in   cs   us sy id wa
3 2 809192 261556 79760 886880 416 0    8244  751   426  863  17 3   6 75
0 3 809188 194916 79820 952900 307 0    21745 1005  1189 2590 34 6  12 48
0 3 809188 162212 79840 988920 95  0    12107 0     1801 2633 2  2   3 94
1 3 809268 88756 79924 1061424 260 28   18377 113   1142 1694 3  5   3 88
1 2 826284 17608 71240 1144180 100 6140 25839 16380 1528 1179 19 9  12 61
2 1 854780 17688 34140 1208980 1   9535 25557 30967 1764 2238 43 13 16 28
0 8 867528 17588 32332 1226392 31  4384 16524 27808 1490 1634 41 10  7 43
4 2 877372 17596 32372 1227532 213 3281 10912 3337  678  932  33 7   3 57
1 2 885980 17800 32408 1239160 204 2892 12347 12681 1033 982  40 12  2 46
5 2 900472 17980 32440 1253884 24  4851 17521 4856  934  1730 48 12 13 26
1 1 904404 17620 32492 1258928 15  1316 7647  15804 919  978  49 9  17 25
4 1 911192 17944 32540 1266724 37  2263 12907 3547  834  1421 47 14 20 20
1 1 919292 17876 31824 1275832 1   2745 16327 2747  617  1421 52 11 23 14
5 0 925216 17812 25008 1289320 12  1975 12760 3181  772  1254 50 10 21 19
0 5 932860 17736 21760 1300280 8   2556 15469 3873  825  1258 49 13 24 15

其中:swpd為虛擬內存的使用大小單位為KB.

     Free為空閒的物理內存的大小(KB);

     Buff為內存中緩存的大小,這些緩存是read()和write()函數使用的(KB);

     Cache進程的地址空間在物理內存中的映射(KB);

     So為從內存寫入swap空間的數據大小(KB);

     Si為從swap空間寫入內存的數據大小(KB);

     Bo為從內存寫入硬盤或swap的頁數量;

     Bi為從硬盤或swap寫入內存的頁數量;

從上面的輸出我們可以看到:

1. 大量的disk pages(bi)被寫入內存,這點可以從cache的不斷增長來證明;

2. 在這個過程中,物理內存始終保持在17MB雖然不斷有數據從硬盤讀入來消耗內存;

3. 為了保持可用物理內存,kswapd不斷的從Buff中偷取內存,來加入空閒列表,buff不斷減小;

4. 同時kswapd不斷的將垃圾頁寫入swap空間,我們可以看到so和swpd不斷增加.

現在我們可以得出結論,這是一個IO Bound的程序,並且造成了虛擬內存的大量使用,加大物理內存可以改善性能.

總結下來:

1. 當一個系統有越少的頁錯誤(所需數據不在內存,需要從硬盤讀入),就會有越好的響應時間.因為內存比硬盤快得多.

2. Free memory數量低是一個好的徵兆,因為證明了cache在起作用,除非同時存在大量的bi和so.

3. 如果一個系統有持續的si和so,就説明系統的內存是一個瓶頸.