1. 程式人生 > >linux 記憶體

linux 記憶體

free 命令顯示系統記憶體的使用情況,包括實體記憶體、交換記憶體(swap)和核心緩衝區記憶體。

如果加上 -h 選項,輸出的結果會友好很多:

有時我們需要持續的觀察記憶體的狀況,此時可以使用 -s 選項並指定間隔的秒數:

$ free -h -s 3

上面的命令每隔 3 秒輸出一次記憶體的使用情況,直到你按下 ctrl + c。

由於 free 命令本身比較簡單,所以本文的重點會放在如何通過 free 命令瞭解系統當前的記憶體使用狀況。

輸出簡介

下面先解釋一下輸出的內容:
Mem 行(第二行)是記憶體的使用情況。
Swap

 行(第三行)是交換空間的使用情況。
total 列顯示系統總的可用實體記憶體和交換空間大小。
used 列顯示已經被使用的實體記憶體和交換空間。
free 列顯示還有多少實體記憶體和交換空間可用使用。
shared 列顯示被共享使用的實體記憶體大小。
buff/cache 列顯示被 buffer 和 cache 使用的實體記憶體大小。
available 列顯示還可以被應用程式使用的實體記憶體大小。

我想只有在理解了一些基本概念之後,上面的輸出才能幫助我們瞭解系統的記憶體狀況。

buff/cache

先來提一個問題: buffer 和 cache 應該是兩種型別的記憶體,但是 free 命令為什麼會把它們放在一起呢?要回答這個問題需要我們做些準備工作。讓我們先來搞清楚 buffer 與 cache 的含義。

buffer 在作業系統中指 buffer cache, 中文一般翻譯為 "緩衝區"。要理解緩衝區,必須明確另外兩個概念:"扇區" 和 "塊"。扇區是裝置的最小定址單元,也叫 "硬扇區" 或 "裝置塊"。塊是作業系統中檔案系統的最小定址單元,也叫 "檔案塊" 或 "I/O 塊"。每個塊包含一個或多個扇區,但大小不能超過一個頁面,所以一個頁可以容納一個或多個記憶體中的塊。當一個塊被調入記憶體時,它要儲存在一個緩衝區中。每個緩衝區與一個塊對應,它相當於是磁碟塊在記憶體中的表示(下圖來自網際網路):

注意,buffer cache 只有塊的概念而沒有檔案的概念,它只是把磁碟上的塊直接搬到記憶體中而不關心塊中究竟存放的是什麼格式的檔案。

cache 在作業系統中指 page cache,中文一般翻譯為 "頁快取記憶體"。頁快取記憶體是核心實現的磁碟快取。它主要用來減少對磁碟的 I/O 操作。具體地講,是通過把磁碟中的資料快取到實體記憶體中,把對磁碟的訪問變為對實體記憶體的訪問。頁快取記憶體快取的是記憶體頁面。快取中的頁來自對普通檔案、塊裝置檔案(這個指的就是 buffer cache 呀)和記憶體對映檔案的讀寫
頁快取記憶體對普通檔案的快取我們可以這樣理解:當核心要讀一個檔案(比如 /etc/hosts)時,它會先檢查這個檔案的資料是不是已經在頁快取記憶體中了。如果在,就放棄訪問磁碟,直接從記憶體中讀取。這個行為稱為快取命中。如果資料不在快取中,就是未命中快取,此時核心就要排程塊 I/O 操作從磁碟去讀取資料。然後核心將讀來的資料放入頁快取記憶體中。這種快取的目標是檔案系統可以識別的檔案(比如 /etc/hosts)。
頁快取記憶體對塊裝置檔案的快取就是我們在前面介紹的 buffer cahce。因為獨立的磁碟塊通過緩衝區也被存入了頁快取記憶體(緩衝區最終是由頁快取記憶體來承載的)。

到這裡我們應該搞清楚了:無論是緩衝區還是頁快取記憶體,它們的實現方式都是一樣的。緩衝區只不過是一種概念上比較特殊的頁快取記憶體罷了。
那麼為什麼 free 命令不直接稱為 cache 而非要寫成 buff/cache? 這是因為緩衝區和頁快取記憶體的實現並非天生就是統一的。在 linux 核心 2.4 中才將它們統一。更早的核心中有兩個獨立的磁碟快取:頁快取記憶體和緩衝區快取記憶體。前者快取頁面,後者快取緩衝區。當你知道了這些故事之後,輸出中列的名稱可能已經不再重要了。

free 與 available

在 free 命令的輸出中,有一個 free 列,同時還有一個 available 列。這二者到底有何區別?
free 是真正尚未被使用的實體記憶體數量。至於 available 就比較有意思了,它是從應用程式的角度看到的可用記憶體數量。Linux 核心為了提升磁碟操作的效能,會消耗一部分記憶體去快取磁碟資料,就是我們介紹的 buffer 和 cache。所以對於核心來說,buffer 和 cache 都屬於已經被使用的記憶體。當應用程式需要記憶體時,如果沒有足夠的 free 記憶體可以用,核心就會從 buffer 和 cache 中回收記憶體來滿足應用程式的請求。所以從應用程式的角度來說,available  = free + buffer + cache。請注意,這只是一個很理想的計算方式,實際中的資料往往有較大的誤差。

交換空間(swap space)

swap space 是磁碟上的一塊區域,可以是一個分割槽,也可以是一個檔案。所以具體的實現可以是 swap 分割槽也可以是 swap 檔案。當系統實體記憶體吃緊時,Linux 會將記憶體中不常訪問的資料儲存到 swap 上,這樣系統就有更多的實體記憶體為各個程序服務,而當系統需要訪問 swap 上儲存的內容時,再將 swap 上的資料載入到記憶體中,這就是常說的換出和換入。交換空間可以在一定程度上緩解記憶體不足的情況,但是它需要讀寫磁碟資料,所以效能不是很高。

現在的機器一般都不太缺記憶體,如果系統預設還是使用了 swap 是不是會拖累系統的效能?理論上是的,但實際上可能性並不是很大。並且核心提供了一個叫做 swappiness 的引數,用於配置需要將記憶體中不常用的資料移到 swap 中去的緊迫程度。這個引數的取值範圍是 0~100,0 告訴核心儘可能的不要將記憶體資料移到 swap 中,也即只有在迫不得已的情況下才這麼做,而 100 告訴核心只要有可能,儘量的將記憶體中不常訪問的資料移到 swap 中。在 ubuntu 系統中,swappiness 的預設值是 60。如果我們覺著記憶體充足,可以在 /etc/sysctl.conf 檔案中設定 swappiness:

vm.swappiness=10

如果系統的記憶體不足,則需要根據實體記憶體的大小來設定交換空間的大小。具體的策略網上有很豐富的資料,這裡筆者不再贅述。

/proc/meminfo 檔案

其實 free 命令中的資訊都來自於 /proc/meminfo 檔案。/proc/meminfo 檔案包含了更多更原始的資訊,只是看起來不太直觀:

$ cat /proc/meminfo

 

有興趣的同學可以直接檢視這個檔案。

發生了什麼?

Linux正借用你未使用的記憶體來做磁碟快取。這使你的計算機看起來可用記憶體很少,但事實不是這樣!一切都很正常!

為什麼這麼做?

磁碟快取使你的系統執行更快更流暢!除了使新手感到困惑,這沒什麼缺點。它從來沒有以任何方式從你的應用拿走記憶體。

如果我想執行更多的應用該怎麼辦?

如果你的應用想要獲取更多的記憶體,系統會從磁碟快取中拿走一塊被借用的記憶體。磁碟快取會立即還給應用!你的計算機可用記憶體的並不少!

我需要更多的交換分割槽(swap)嗎?

不需要,磁碟快取僅會借用應用目前不需要的記憶體。它不會使用交換分割槽。如果應用需要更多的記憶體,系統會從磁碟快取中拿回來。系統不會使用交換分割槽。

我如何讓Linux停止這樣做?

你不能禁用磁碟快取。任何人想要禁用磁碟快取的唯一理由是他認為這從他的應用中拿走了記憶體,但事實不是這樣!磁碟快取可以讓應用載入更快並且執行更加流暢,但它卻從來沒有拿走記憶體!因此,沒有任何理由去禁用它!

如果不是這樣,為什麼topfree命令說我所有的記憶體已被使用?

這僅僅是用辭的差異。你和Linux系統一致認為被應用佔用的記憶體稱為used,而沒有被任何程式使用的部分稱為free

但是,你認為目前被佔用但仍然可以被應用使用的記憶體稱作什麼呢?

你可能認為這部分記憶體是freeavailable。而Linux系統稱它usedavailable:

記憶體 你稱它 Linux稱它
被應用使用 used used
被佔用,但可以使用 free(或available) used(或available)
沒有用來做任何事 free free

譯註:老版free命令中被佔用但可以使用的記憶體稱為used(used中的一部分,即buffers+cached), 而新版的free命令中稱之為available

不嚴格來講,topfree命令稱這部分記憶體為bufferscached。因為你和Linux用辭的差異,你可能認為你的計算機可用記憶體很少,不過事實並非如此。

譯註:這部分記憶體準確來說是新版本free命令中的available或者是新版本top命令中的avail Mem

我怎麼看我真正還有多少可用記憶體?

為了弄明白除了交換分割槽外你的應用可以使用多少記憶體,執行free -m命令,然後檢視available那一列:

$ free -m
              total        used        free      shared  buff/cache   available
Mem:           1504        1491          13           0         855      792
Swap:          2047           6        2041

(2016年之前的Linux安裝版本,在-/+ buffers/cache那排檢視free列)

這是你以MB為單位的答案。如果你天真地檢視usedfree,你會認為你的記憶體幾乎快佔滿達到99%,然而實際僅僅只有47%!

如果想檢視更詳細、更專業的關於Linux統計available記憶體大小的描述,請看the commit that added the field.

什麼時候我該開始擔心?

一個擁有足夠記憶體的、執行良好的Linux系統在執行一段時間後會表現出以下預期的無害特徵:

  • free記憶體接近於0
  • used記憶體接近總共記憶體
  • available記憶體(或者是free + buffers/cache)有足夠空間(比如說:總記憶體的20%以上)
  • swap used沒有發生變化

真正的記憶體不夠、你也許想調查原因的情形,警告標誌如下:

  • available記憶體(或者是free + buffers/cache)接近於0
  • swap used在增加或者波動
  • dmesg | grep oom-killer命令顯示OutOfMemory-killer程式正在執行

我如何驗證這些?

如果想了解更多細節和做實驗測試磁碟快取的影響,請看這個頁面。我做了少量的工作只是想讓你感激磁碟快取,而不是讓你測試你的硬體速度提升了幾個數量級。

Experiments and fun with the Linux disk cache

Hopefully you are now convinced that Linux didn't just eat your ram. Here are some interesting things you can do to learn how the disk cache works.

Effects of disk cache on application memory allocation

Since I've already promised that disk cache doesn't prevent applications from getting the memory they want, let's start with that. Here is a C app (munch.c) that gobbles up as much memory as it can, or to a specified limit:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main(int argc, char** argv) {
    int max = -1;
    int mb = 0;
    char* buffer;

    if(argc > 1)
        max = atoi(argv[1]);

    while((buffer=malloc(1024*1024)) != NULL && mb != max) {
        memset(buffer, 0, 1024*1024);
        mb++;
        printf("Allocated %d MB\n", mb);
    }

    return 0;
}

Running out of memory isn't fun, but the OOM killer should end just this process and hopefully the rest will remain undisturbed. We'll definitely want to disable swap for this, or the app will gobble up that as well.

$ sudo swapoff -a

$ free -m

(note that your free output could be different, and have an 'available' column instead of a '-/+' row)

             total       used       free     shared    buffers     cached
Mem:          1504       1490         14          0         24        809
-/+ buffers/cache:        656        848
Swap:            0          0          0


$ gcc munch.c -o munch

$ ./munch
Allocated 1 MB
Allocated 2 MB
(...)
Allocated 877 MB
Allocated 878 MB
Allocated 879 MB
Killed

$ free -m
             total       used       free     shared    buffers     cached
Mem:          1504        650        854          0          1         67
-/+ buffers/cache:        581        923
Swap:            0          0          0

$

Even though it said 14MB "free", that didn't stop the application from grabbing 879MB. Afterwards, the cache is pretty empty2, but it will gradually fill up again as files are read and written. Give it a try.

Effects of disk cache on swapping

I also said that disk cache won't cause applications to use swap. Let's try that as well, with the same 'munch' app as in the last experiment. This time we'll run it with swap on, and limit it to a few hundred megabytes:

$ free -m
             total       used       free     shared    buffers     cached
Mem:          1504       1490         14          0         10        874
-/+ buffers/cache:        605        899
Swap:         2047          6       2041

$ ./munch 400
Allocated 1 MB
Allocated 2 MB
(...)
Allocated 399 MB
Allocated 400 MB

$ free -m
             total       used       free     shared    buffers     cached
Mem:          1504       1090        414          0          5        485
-/+ buffers/cache:        598        906
Swap:         2047          6       2041

munch ate 400MB of ram, which was taken from the disk cache without resorting to swap. Likewise, we can fill the disk cache again and it will not start eating swap either. If you run watch free -m in one terminal, and find . -type f -exec cat {} + > /dev/null in another, you can see that "cached" will rise while "free" falls. After a while, it tapers off but swap is never touched1

Clearing the disk cache

For experimentation, it's very convenient to be able to drop the disk cache. For this, we can use the special file /proc/sys/vm/drop_caches. By writing 3 to it, we can clear most of the disk cache:

$ free -m
             total       used       free     shared    buffers     cached
Mem:          1504       1471         33          0         36        801
-/+ buffers/cache:        633        871
Swap:         2047          6       2041

$ echo 3 | sudo tee /proc/sys/vm/drop_caches 
3

$ free -m
             total       used       free     shared    buffers     cached
Mem:          1504        763        741          0          0        134
-/+ buffers/cache:        629        875
Swap:         2047          6       2041

Notice how "buffers" and "cached" went down, free mem went up, and free+buffers/cache stayed the same.

Effects of disk cache on load times

Let's make two test programs, one in Python and one in Java. Python and Java both come with pretty big runtimes, which have to be loaded in order to run the application. This is a perfect scenario for disk cache to work its magic.

$ cat hello.py
print "Hello World! Love, Python"

$ cat Hello.java
class Hello {
    public static void main(String[] args) throws Exception {
        System.out.println("Hello World! Regards, Java");
    }
}

$ javac Hello.java

$ python hello.py
Hello World! Love, Python

$ java Hello
Hello World! Regards, Java

$

Our hello world apps work. Now let's drop the disk cache, and see how long it takes to run them.

$ echo 3 | sudo tee /proc/sys/vm/drop_caches
3

$ time python hello.py
Hello World! Love, Python

real	0m1.026s
user	0m0.020s
sys	    0m0.020s

$ time java Hello
Hello World! Regards, Java

real	0m2.174s
user	0m0.100s
sys	    0m0.056s

$

Wow. 1 second for Python, and 2 seconds for Java? That's a lot just to say hello. However, now all the file required to run them will be in the disk cache so they can be fetched straight from memory. Let's try again:

$ time python hello.py
Hello World! Love, Python

real    0m0.022s
user    0m0.016s
sys     0m0.008s

$ time java Hello
Hello World! Regards, Java

real    0m0.139s
user    0m0.060s
sys     0m0.028s

$

Yay! Python now runs in just 22 milliseconds, while java uses 139ms. That's 45 and 15 times faster! All your apps get this boost automatically!

Effects of disk cache on file reading

Let's make a big file and see how disk cache affects how fast we can read it. I'm making a 200mb file, but if you have less free ram, you can adjust it.

$ echo 3 | sudo tee /proc/sys/vm/drop_caches
3

$ free -m
             total       used       free     shared    buffers     cached
Mem:          1504        546        958          0          0         85
-/+ buffers/cache:        461       1043
Swap:         2047          6       2041

$ dd if=/dev/zero of=bigfile bs=1M count=200
200+0 records in
200+0 records out
209715200 bytes (210 MB) copied, 6.66191 s, 31.5 MB/s

$ ls -lh bigfile
-rw-r--r-- 1 vidar vidar 200M 2009-04-25 12:30 bigfile

$ free -m
             total       used       free     shared    buffers     cached
Mem:          1504        753        750          0          0        285
-/+ buffers/cache:        468       1036
Swap:         2047          6       2041

$

Since the file was just written, it will go in the disk cache. The 200MB file caused a 200MB bump in "cached". Let's read it, clear the cache, and read it again to see how fast it is:

$ time cat bigfile > /dev/null

real    0m0.139s
user    0m0.008s
sys     0m0.128s

$ echo 3 | sudo tee /proc/sys/vm/drop_caches
3

$ time cat bigfile > /dev/null

real    0m8.688s
user    0m0.020s
sys     0m0.336s

$

That's more than fifty times faster!

Conclusions

The Linux disk cache is very unobtrusive. It uses spare memory to greatly increase disk access speeds, and without taking any memory away from applications. A fully used store of ram on Linux is efficient hardware use, not a warning sign.

LinuxAteMyRam.com was presented by VidarHolen.net

These pages do simplify a little:

    1. While newly allocated memory will always (though see point #2) be taken from the disk cache instead of swap, Linux can be configured to preemptively swap out other unused applications in the background to free up memory for cache. The is tunable through the 'swappiness' setting, accessible through /proc/sys/vm/swappiness.

      A server might want to swap out unused apps to speed up disk access of running ones (making the system faster), while a desktop system might want to keep apps in memory to prevent lag when the user finally uses them (making the system more responsive). This is the subject of much debate.

  1. Some parts of the cache can't be dropped, not even to accomodate new applications. This includes mmap'd pages that have been mlocked by some application, dirty pages that have not yet been written to storage, and data stored in tmpfs (including /dev/shm, used for shared memory). The mmap'd, mlocked pages are stuck in the page cache. Dirty pages will for the most part swiftly be written out. Data in tmpfs will be swapped out if possible.

  參考:https://www.cnblogs.com/ultranms/p/9254160.html  https://www.linuxatemyram.com/play.html  https://www.cnblogs.com/thinkam/p/8407043.html

 

如果加上 -h 選項,輸出的結果會友好很多:

有時我們需要持續的觀察記憶體的狀況,此時可以使用 -s 選項並指定間隔的秒數:

$ free -h -s 3

上面的命令每隔 3 秒輸出一次記憶體的使用情況,直到你按下 ctrl + c。

由於 free 命令本身比較簡單,所以本文的重點會放在如何通過 free 命令瞭解系統當前的記憶體使用狀況。

輸出簡介

下面先解釋一下輸出的內容:
Mem 行(第二行)是記憶體的使用情況。
Swap 行(第三行)是交換空間的使用情況。
total 列顯示系統總的可用實體記憶體和交換空間大小。
used 列顯示已經被使用的實體記憶體和交換空間。
free 列顯示還有多少實體記憶體和交換空間可用使用。
shared 列顯示被共享使用的實體記憶體大小。
buff/cache 列顯示被 buffer 和 cache 使用的實體記憶體大小。
available 列顯示還可以被應用程式使用的實體記憶體大小。

我想只有在理解了一些基本概念之後,上面的輸出才能幫助我們瞭解系統的記憶體狀況。

buff/cache

先來提一個問題: buffer 和 cache 應該是兩種型別的記憶體,但是 free 命令為什麼會把它們放在一起呢?要回答這個問題需要我們做些準備工作。讓我們先來搞清楚 buffer 與 cache 的含義。

buffer 在作業系統中指 buffer cache, 中文一般翻譯為 "緩衝區"。要理解緩衝區,必須明確另外兩個概念:"扇區" 和 "塊"。扇區是裝置的最小定址單元,也叫 "硬扇區" 或 "裝置塊"。塊是作業系統中檔案系統的最小定址單元,也叫 "檔案塊" 或 "I/O 塊"。每個塊包含一個或多個扇區,但大小不能超過一個頁面,所以一個頁可以容納一個或多個記憶體中的塊。當一個塊被調入記憶體時,它要儲存在一個緩衝區中。每個緩衝區與一個塊對應,它相當於是磁碟塊在記憶體中的表示(下圖來自網際網路):

注意,buffer cache 只有塊的概念而沒有檔案的概念,它只是把磁碟上的塊直接搬到記憶體中而不關心塊中究竟存放的是什麼格式的檔案。

cache 在作業系統中指 page cache,中文一般翻譯為 "頁快取記憶體"。頁快取記憶體是核心實現的磁碟快取。它主要用來減少對磁碟的 I/O 操作。具體地講,是通過把磁碟中的資料快取到實體記憶體中,把對磁碟的訪問變為對實體記憶體的訪問。頁快取記憶體快取的是記憶體頁面。快取中的頁來自對普通檔案、塊裝置檔案(這個指的就是 buffer cache 呀)和記憶體對映檔案的讀寫
頁快取記憶體對普通檔案的快取我們可以這樣理解:當核心要讀一個檔案(比如 /etc/hosts)時,它會先檢查這個檔案的資料是不是已經在頁快取記憶體中了。如果在,就放棄訪問磁碟,直接從記憶體中讀取。這個行為稱為快取命中。如果資料不在快取中,就是未命中快取,此時核心就要排程塊 I/O 操作從磁碟去讀取資料。然後核心將讀來的資料放入頁快取記憶體中。這種快取的目標是檔案系統可以識別的檔案(比如 /etc/hosts)。
頁快取記憶體對塊裝置檔案的快取就是我們在前面介紹的 buffer cahce。因為獨立的磁碟塊通過緩衝區也被存入了頁快取記憶體(緩衝區最終是由頁快取記憶體來承載的)。

到這裡我們應該搞清楚了:無論是緩衝區還是頁快取記憶體,它們的實現方式都是一樣的。緩衝區只不過是一種概念上比較特殊的頁快取記憶體罷了。
那麼為什麼 free 命令不直接稱為 cache 而非要寫成 buff/cache? 這是因為緩衝區和頁快取記憶體的實現並非天生就是統一的。在 linux 核心 2.4 中才將它們統一。更早的核心中有兩個獨立的磁碟快取:頁快取記憶體和緩衝區快取記憶體。前者快取頁面,後者快取緩衝區。當你知道了這些故事之後,輸出中列的名稱可能已經不再重要了。

free 與 available

在 free 命令的輸出中,有一個 free 列,同時還有一個 available 列。這二者到底有何區別?
free 是真正尚未被使用的實體記憶體數量。至於 available 就比較有意思了,它是從應用程式的角度看到的可用記憶體數量。Linux 核心為了提升磁碟操作的效能,會消耗一部分記憶體去快取磁碟資料,就是我們介紹的 buffer 和 cache。所以對於核心來說,buffer 和 cache 都屬於已經被使用的記憶體。當應用程式需要記憶體時,如果沒有足夠的 free 記憶體可以用,核心就會從 buffer 和 cache 中回收記憶體來滿足應用程式的請求。所以從應用程式的角度來說,available  = free + buffer + cache。請注意,這只是一個很理想的計算方式,實際中的資料往往有較大的誤差。

交換空間(swap space)

swap space 是磁碟上的一塊區域,可以是一個分割槽,也可以是一個檔案。所以具體的實現可以是 swap 分割槽也可以是 swap 檔案。當系統實體記憶體吃緊時,Linux 會將記憶體中不常訪問的資料儲存到 swap 上,這樣系統就有更多的實體記憶體為各個程序服務,而當系統需要訪問 swap 上儲存的內容時,再將 swap 上的資料載入到記憶體中,這就是常說的換出和換入。交換空間可以在一定程度上緩解記憶體不足的情況,但是它需要讀寫磁碟資料,所以效能不是很高。

現在的機器一般都不太缺記憶體,如果系統預設還是使用了 swap 是不是會拖累系統的效能?理論上是的,但實際上可能性並不是很大。並且核心提供了一個叫做 swappiness 的引數,用於配置需要將記憶體中不常用的資料移到 swap 中去的緊迫程度。這個引數的取值範圍是 0~100,0 告訴核心儘可能的不要將記憶體資料移到 swap 中,也即只有在迫不得已的情況下才這麼做,而 100 告訴核心只要有可能,儘量的將記憶體中不常訪問的資料移到 swap 中。在 ubuntu 系統中,swappiness 的預設值是 60。如果我們覺著記憶體充足,可以在 /etc/sysctl.conf 檔案中設定 swappiness:

vm.swappiness=10

如果系統的記憶體不足,則需要根據實體記憶體的大小來設定交換空間的大小。具體的策略網上有很豐富的資料,這裡筆者不再贅述。

/proc/meminfo 檔案

其實 free 命令中的資訊都來自於 /proc/meminfo 檔案。/proc/meminfo 檔案包含了更多更原始的資訊,只是看起來不太直觀:

$ cat /proc/meminfo

 

有興趣的同學可以直接檢視這個檔案。

發生了什麼?

Linux正借用你未使用的記憶體來做磁碟快取。這使你的計算機看起來可用記憶體很少,但事實不是這樣!一切都很正常!

為什麼這麼做?

磁碟快取使你的系統執行更快更流暢!除了使新手感到困惑,這沒什麼缺點。它從來沒有以任何方式從你的應用拿走記憶體。

如果我想執行更多的應用該怎麼辦?

如果你的應用想要獲取更多的記憶體,系統會從磁碟快取中拿走一塊被借用的記憶體。磁碟快取會立即還給應用!你的計算機可用記憶體的並不少!

我需要更多的交換分割槽(swap)嗎?

不需要,磁碟快取僅會借用應用目前不需要的記憶體。它不會使用交換分割槽。如果應用需要更多的記憶體,系統會從磁碟快取中拿回來。系統不會使用交換分割槽。

我如何讓Linux停止這樣做?

你不能禁用磁碟快取。任何人想要禁用磁碟快取的唯一理由是他認為這從他的應用中拿走了記憶體,但事實不是這樣!磁碟快取可以讓應用載入更快並且執行更加流暢,但它卻從來沒有拿走記憶體!因此,沒有任何理由去禁用它!

如果不是這樣,為什麼topfree命令說我所有的記憶體已被使用?

這僅僅是用辭的差異。你和Linux系統一致認為被應用佔用的記憶體稱為used,而沒有被任何程式使用的部分稱為free

但是,你認為目前被佔用但仍然可以被應用使用的記憶體稱作什麼呢?

你可能認為這部分記憶體是freeavailable。而Linux系統稱它usedavailable:

記憶體 你稱它 Linux稱它
被應用使用 used used
被佔用,但可以使用 free(或available) used(或available)
沒有用來做任何事 free free

譯註:老版free命令中被佔用但可以使用的記憶體稱為used(used中的一部分,即buffers+cached), 而新版的free命令中稱之為available

不嚴格來講,topfree命令稱這部分記憶體為bufferscached。因為你和Linux用辭的差異,你可能認為你的計算機可用記憶體很少,不過事實並非如此。

譯註:這部分記憶體準確來說是新版本free命令中的available或者是新版本top命令中的avail Mem

我怎麼看我真正還有多少可用記憶體?

為了弄明白除了交換分割槽外你的應用可以使用多少記憶體,執行free -m命令,然後檢視available那一列:

$ free -m
              total        used        free      shared  buff/cache   available
Mem:           1504        1491          13           0         855      792
Swap:          2047           6        2041

(2016年之前的Linux安裝版本,在-/+ buffers/cache那排檢視free列)

這是你以MB為單位的答案。如果你天真地檢視usedfree,你會認為你的記憶體幾乎快佔滿達到99%,然而實際僅僅只有47%!

如果想檢視更詳細、更專業的關於Linux統計available記憶體大小的描述,請看the commit that added the field.

什麼時候我該開始擔心?

一個擁有足夠記憶體的、執行良好的Linux系統在執行一段時間後會表現出以下預期的無害特徵:

  • free記憶體接近於0
  • used記憶體接近總共記憶體
  • available記憶體(或者是free + buffers/cache)有足夠空間(比如說:總記憶體的20%以上)
  • swap used沒有發生變化

真正的記憶體不夠、你也許想調查原因的情形,警告標誌如下:

  • available記憶體(或者是free + buffers/cache)接近於0
  • swap used在增加或者波動
  • dmesg | grep oom-killer命令顯示OutOfMemory-killer程式正在執行

我如何驗證這些?

如果想了解更多細節和做實驗測試磁碟快取的影響,請看這個頁面。我做了少量的工作只是想讓你感激磁碟快取,而不是讓你測試你的硬體速度提升了幾個數量級。

Experiments and fun with the Linux disk cache

Hopefully you are now convinced that Linux didn't just eat your ram. Here are some interesting things you can do to learn how the disk cache works.

Effects of disk cache on application memory allocation

Since I've already promised that disk cache doesn't prevent applications from getting the memory they want, let's start with that. Here is a C app (munch.c) that gobbles up as much memory as it can, or to a specified limit:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main(int argc, char** argv) {
    int max = -1;
    int mb = 0;
    char* buffer;

    if(argc > 1)
        max = atoi(argv[1]);

    while((buffer=malloc(1024*1024)) != NULL && mb != max) {
        memset(buffer, 0, 1024*1024);
        mb++;
        printf("Allocated %d MB\n", mb);
    }

    return 0;
}

Running out of memory isn't fun, but the OOM killer should end just this process and hopefully the rest will remain undisturbed. We'll definitely want to disable swap for this, or the app will gobble up that as well.

$ sudo swapoff -a

$ free -m

(note that your free output could be different, and have an 'available' column instead of a '-/+' row)

             total       used       free     shared    buffers     cached
Mem:          1504       1490         14          0         24        809
-/+ buffers/cache:        656        848
Swap:            0          0          0


$ gcc munch.c -o munch

$ ./munch
Allocated 1 MB
Allocated 2 MB
(...)
Allocated 877 MB
Allocated 878 MB
Allocated 879 MB
Killed

$ free -m
             total       used       free     shared    buffers     cached
Mem:          1504        650        854          0          1         67
-/+ buffers/cache:        581        923
Swap:            0          0          0

$

Even though it said 14MB "free", that didn't stop the application from grabbing 879MB. Afterwards, the cache is pretty empty2, but it will gradually fill up again as files are read and written. Give it a try.

Effects of disk cache on swapping

I also said that disk cache won't cause applications to use swap. Let's try that as well, with the same 'munch' app as in the last experiment. This time we'll run it with swap on, and limit it to a few hundred megabytes:

$ free -m
             total       used       free     shared    buffers     cached
Mem:          1504       1490         14          0         10        874
-/+ buffers/cache:        605        899
Swap:         2047          6       2041

$ ./munch 400
Allocated 1 MB
Allocated 2 MB
(...)
Allocated 399 MB
Allocated 400 MB

$ free -m
             total       used       free     shared    buffers     cached
Mem:          1504       1090        414          0          5        485
-/+ buffers/cache:        598        906
Swap:         2047          6       2041

munch ate 400MB of ram, which was taken from the disk cache without resorting to swap. Likewise, we can fill the disk cache again and it will not start eating swap either. If you run watch free -m in one terminal, and find . -type f -exec cat {} + > /dev/null in another, you can see that "cached" will rise while "free" falls. After a while, it tapers off but swap is never touched1

Clearing the disk cache

For experimentation, it's very convenient to be able to drop the disk cache. For this, we can use the special file /proc/sys/vm/drop_caches. By writing 3 to it, we can clear most of the disk cache:

$ free -m
             total       used       free     shared    buffers     cached
Mem:          1504       1471         33          0         36        801
-/+ buffers/cache:        633        871
Swap:         2047          6       2041

$ echo 3 | sudo tee /proc/sys/vm/drop_caches 
3

$ free -m
             total       used       free     shared    buffers     cached
Mem:          1504        763        741          0          0        134
-/+ buffers/cache:        629        875
Swap:         2047          6       2041

Notice how "buffers" and "cached" went down, free mem went up, and free+buffers/cache stayed the same.

Effects of disk cache on load times

Let's make two test programs, one in Python and one in Java. Python and Java both come with pretty big runtimes, which have to be loaded in order to run the application. This is a perfect scenario for disk cache to work its magic.

$ cat hello.py
print "Hello World! Love, Python"

$ cat Hello.java
class Hello {
    public static void main(String[] args) throws Exception {
        System.out.println("Hello World! Regards, Java");
    }
}

$ javac Hello.java

$ python hello.py
Hello World! Love, Python

$ java Hello
Hello World! Regards, Java

$

Our hello world apps work. Now let's drop the disk cache, and see how long it takes to run them.

$ echo 3 | sudo tee /proc/sys/vm/drop_caches
3

$ time python hello.py
Hello World! Love, Python

real	0m1.026s
user	0m0.020s
sys	    0m0.020s

$ time java Hello
Hello World! Regards, Java

real	0m2.174s
user	0m0.100s
sys	    0m0.056s

$

Wow. 1 second for Python, and 2 seconds for Java? That's a lot just to say hello. However, now all the file required to run them will be in the disk cache so they can be fetched straight from memory. Let's try again:

$ time python hello.py
Hello World! Love, Python

real    0m0.022s
user    0m0.016s
sys     0m0.008s

$ time java Hello
Hello World! Regards, Java

real    0m0.139s
user    0m0.060s
sys     0m0.028s

$

Yay! Python now runs in just 22 milliseconds, while java uses 139ms. That's 45 and 15 times faster! All your apps get this boost automatically!

Effects of disk cache on file reading

Let's make a big file and see how disk cache affects how fast we can read it. I'm making a 200mb file, but if you have less free ram, you can adjust it.

$ echo 3 | sudo tee /proc/sys/vm/drop_caches
3

$ free -m
             total       used       free     shared    buffers     cached
Mem:          1504        546        958          0          0         85
-/+ buffers/cache:        461       1043
Swap:         2047          6       2041

$ dd if=/dev/zero of=bigfile bs=1M count=200
200+0 records in
200+0 records out
209715200 bytes (210 MB) copied, 6.66191 s, 31.5 MB/s

$ ls -lh bigfile
-rw-r--r-- 1 vidar vidar 200M 2009-04-25 12:30 bigfile

$ free -m
             total       used       free     shared    buffers     cached
Mem:          1504        753        750          0          0        285
-/+ buffers/cache:        468       1036
Swap:         2047          6       2041

$

Since the file was just written, it will go in the disk cache. The 200MB file caused a 200MB bump in "cached". Let's read it, clear the cache, and read it again to see how fast it is:

$ time cat bigfile > /dev/null

real    0m0.139s
user    0m0.008s
sys     0m0.128s

$ echo 3 | sudo tee /proc/sys/vm/drop_caches
3

$ time cat bigfile > /dev/null

real    0m8.688s
user    0m0.020s
sys     0m0.336s

$

That's more than fifty times faster!

Conclusions

The Linux disk cache is very unobtrusive. It uses spare memory to greatly increase disk access speeds, and without taking any memory away from applications. A fully used store of ram on Linux is efficient hardware use, not a warning sign.

LinuxAteMyRam.com was presented by VidarHolen.net

These pages do simplify a little:

    1. While newly allocated memory will always (though see point #2) be taken from the disk cache instead of swap, Linux can be configured to preemptively swap out other unused applications in the background to free up memory for cache. The is tunable through the 'swappiness' setting, accessible through /proc/sys/vm/swappiness.

      A server might want to swap out unused apps to speed up disk access of running ones (making the system faster), while a desktop system might want to keep apps in memory to prevent lag when the user finally uses them (making the system more responsive). This is the subject of much debate.

  1. Some parts of the cache can't be dropped, not even to accomodate new applications. This includes mmap'd pages that have been mlocked by some application, dirty pages that have not yet been written to storage, and data stored in tmpfs (including /dev/shm, used for shared memory). The mmap'd, mlocked pages are stuck in the page cache. Dirty pages will for the most part swiftly be written out. Data in tmpfs will be swapped out if possible.

  參考:https://www.cnblogs.com/ultranms/p/9254160.html  https://www.linuxatemyram.com/play.html  https://www.cnblogs.com/thinkam/p/8407043.html

 

如果加上 -h 選項,輸出的結果會友好很多:

有時我們需要持續的觀察記憶體的狀況,此時可以使用 -s 選項並指定間隔的秒數:

$ free -h -s 3

上面的命令每隔 3 秒輸出一次記憶體的使用情況,直到你按下 ctrl + c。

由於 free 命令本身比較簡單,所以本文的重點會放在如何通過 free 命令瞭解系統當前的記憶體使用狀況。

輸出簡介

下面先解釋一下輸出的內容:
Mem 行(第二行)是記憶體的使用情況。
Swap 行(第三行)是交換空間的使用情況。
total 列顯示系統總的可用實體記憶體和交換空間大小。
used 列顯示已經被使用的實體記憶體和交換空間。
free 列顯示還有多少實體記憶體和交換空間可用使用。
shared 列顯示被共享使用的實體記憶體大小。
buff/cache 列顯示被 buffer 和 cache 使用的實體記憶體大小。
available 列顯示還可以被應用程式使用的實體記憶體大小。

我想只有在理解了一些基本概念之後,上面的輸出才能幫助我們瞭解系統的記憶體狀況。

buff/cache

先來提一個問題: buffer 和 cache 應該是兩種型別的記憶體,但是 free 命令為什麼會把它們放在一起呢?要回答這個問題需要我們做些準備工作。讓我們先來搞清楚 buffer 與 cache 的含義。

buffer 在作業系統中指 buffer cache, 中文一般翻譯為 "緩衝區"。要理解緩衝區,必須明確另外兩個概念:"扇區" 和 "塊"。扇區是裝置的最小定址單元,也叫 "硬扇區" 或 "裝置塊"。塊是作業系統中檔案系統的最小定址單元,也叫 "檔案塊" 或 "I/O 塊"。每個塊包含一個或多個扇區,但大小不能超過一個頁面,所以一個頁可以容納一個或多個記憶體中的塊。當一個塊被調入記憶體時,它要儲存在一個緩衝區中。每個緩衝區與一個塊對應,它相當於是磁碟塊在記憶體中的表示(下圖來自網際網路):

注意,buffer cache 只有塊的概念而沒有檔案的概念,它只是把磁碟上的塊直接搬到記憶體中而不關心塊中究竟存放的是什麼格式的檔案。

cache 在作業系統中指 page cache,中文一般翻譯為 "頁快取記憶體"。頁快取記憶體是核心實現的磁碟快取。它主要用來減少對磁碟的 I/O 操作。具體地講,是通過把磁碟中的資料快取到實體記憶體中,把對磁碟的訪問變為對實體記憶體的訪問。頁快取記憶體快取的是記憶體頁面。快取中的頁來自對普通檔案、塊裝置檔案(這個指的就是 buffer cache 呀)和記憶體對映檔案的讀寫
頁快取記憶體對普通檔案的快取我們可以這樣理解:當核心要讀一個檔案(比如 /etc/hosts)時,它會先檢查這個檔案的資料是不是已經在頁快取記憶體中了。如果在,就放棄訪問磁碟,直接從記憶體中讀取。這個行為稱為快取命中。如果資料不在快取中,就是未命中快取,此時核心就要排程塊 I/O 操作從磁碟去讀取資料。然後核心將讀來的資料放入頁快取記憶體中。這種快取的目標是檔案系統可以識別的檔案(比如 /etc/hosts)。
頁快取記憶體對塊裝置檔案的快取就是我們在前面介紹的 buffer cahce。因為獨立的磁碟塊通過緩衝區也被存入了頁快取記憶體(緩衝區最終是由頁快取記憶體來承載的)。

到這裡我們應該搞清楚了:無論是緩衝區還是頁快取記憶體,它們的實現方式都是一樣的。緩衝區只不過是一種概念上比較特殊的頁快取記憶體罷了。
那麼為什麼 free 命令不直接稱為 cache 而非要寫成 buff/cache? 這是因為緩衝區和頁快取記憶體的實現並非天生就是統一的。在 linux 核心 2.4 中才將它們統一。更早的核心中有兩個獨立的磁碟快取:頁快取記憶體和緩衝區快取記憶體。前者快取頁面,後者快取緩衝區。當你知道了這些故事之後,輸出中列的名稱可能已經不再重要了。

free 與 available

在 free 命令的輸出中,有一個 free 列,同時還有一個 available 列。這二者到底有何區別?
free 是真正尚未被使用的實體記憶體數量。至於 available 就比較有意思了,它是從應用程式的角度看到的可用記憶體數量。Linux 核心為了提升磁碟操作的效能,會消耗一部分記憶體去快取磁碟資料,就是我們介紹的 buffer 和 cache。所以對於核心來說,buffer 和 cache 都屬於已經被使用的記憶體。當應用程式需要記憶體時,如果沒有足夠的 free 記憶體可以用,核心就會從 buffer 和 cache 中回收記憶體來滿足應用程式的請求。所以從應用程式的角度來說,available  = free + buffer + cache。請注意,這只是一個很理想的計算方式,實際中的資料往往有較大的誤差。

交換空間(swap space)

swap space 是磁碟上的一塊區域,可以是一個分割槽,也可以是一個檔案。所以具體的實現可以是 swap 分割槽也可以是 swap 檔案。當系統實體記憶體吃緊時,Linux 會將記憶體中不常訪問的資料儲存到 swap 上,這樣系統就有更多的實體記憶體為各個程序服務,而當系統需要訪問 swap 上儲存的內容時,再將 swap 上的資料載入到記憶體中,這就是常說的換出和換入。交換空間可以在一定程度上緩解記憶體不足的情況,但是它需要讀寫磁碟資料,所以效能不是很高。

現在的機器一般都不太缺記憶體,如果系統預設還是使用了 swap 是不是會拖累系統的效能?理論上是的,但實際上可能性並不是很大。並且核心提供了一個叫做 swappiness 的引數,用於配置需要將記憶體中不常用的資料移到 swap 中去的緊迫程度。這個引數的取值範圍是 0~100,0 告訴核心儘可能的不要將記憶體資料移到 swap 中,也即只有在迫不得已的情況下才這麼做,而 100 告訴核心只要有可能,儘量的將記憶體中不常訪問的資料移到 swap 中。在 ubuntu 系統中,swappiness 的預設值是 60。如果我們覺著記憶體充足,可以在 /etc/sysctl.conf 檔案中設定 swappiness:

vm.swappiness=10

如果系統的記憶體不足,則需要根據實體記憶體的大小來設定交換空間的大小。具體的策略網上有很豐富的資料,這裡筆者不再贅述。

/proc/meminfo 檔案

其實 free 命令中的資訊都來自於 /proc/meminfo 檔案。/proc/meminfo 檔案包含了更多更原始的資訊,只是看起來不太直觀:

$ cat /proc/meminfo

 

有興趣的同學可以直接檢視這個檔案。

發生了什麼?

Linux正借用你未使用的記憶體來做磁碟快取。這使你的計算機看起來可用記憶體很少,但事實不是這樣!一切都很正常!

為什麼這麼做?

磁碟快取使你的系統執行更快更流暢!除了使新手感到困惑,這沒什麼缺點。它從來沒有以任何方式從你的應用拿走記憶體。

如果我想執行更多的應用該怎麼辦?

如果你的應用想要獲取更多的記憶體,系統會從磁碟快取中拿走一塊被借用的記憶體。磁碟快取會立即還給應用!你的計算機可用記憶體的並不少!

我需要更多的交換分割槽(swap)嗎?

不需要,磁碟快取僅會借用應用目前不需要的記憶體。它不會使用交換分割槽。如果應用需要更多的記憶體,系統會從磁碟快取中拿回來。系統不會使用交換分割槽。

我如何讓Linux停止這樣做?

你不能禁用磁碟快取。任何人想要禁用磁碟快取的唯一理由是他認為這從他的應用中拿走了記憶體,但事實不是這樣!磁碟快取可以讓應用載入更快並且執行更加流暢,但它卻從來沒有拿走記憶體!因此,沒有任何理由去禁用它!

如果不是這樣,為什麼topfree命令說我所有的記憶體已被使用?

這僅僅是用辭的差異。你和Linux系統一致認為被應用佔用的記憶體稱為used,而沒有被任何程式使用的部分稱為free

但是,你認為目前被佔用但仍然可以被應用使用的記憶體稱作什麼呢?

你可能認為這部分記憶體是freeavailable。而Linux系統稱它usedavailable:

記憶體 你稱它 Linux稱它
被應用使用 used used
被佔用,但可以使用 free(或available) used(或available)
沒有用來做任何事 free free

譯註:老版free命令中被佔用但可以使用的記憶體稱為used(used中的一部分,即buffers+cached), 而新版的free命令中稱之為available

不嚴格來講,topfree命令稱這部分記憶體為bufferscached。因為你和Linux用辭的差異,你可能認為你的計算機可用記憶體很少,不過事實並非如此。

譯註:這部分記憶體準確來說是新版本free命令中的available或者是新版本top命令中的avail Mem

我怎麼看我真正還有多少可用記憶體?

為了弄明白除了交換分割槽外你的應用可以使用多少記憶體,執行free -m命令,然後檢視available那一列:

$ free -m
              total        used        free      shared  buff/cache   available
Mem:           1504        1491          13           0         855      792
Swap:          2047           6        2041

(2016年之前的Linux安裝版本,在-/+ buffers/cache那排檢視free列)

這是你以MB為單位的答案。如果你天真地檢視usedfree,你會認為你的記憶體幾乎快佔滿達到99%,然而實際僅僅只有47%!

如果想檢視更詳細、更專業的關於Linux統計available記憶體大小的描述,請看the commit that added the field.

什麼時候我該開始擔心?

一個擁有足夠記憶體的、執行良好的Linux系統在執行一段時間後會表現出以下預期的無害特徵:

  • free記憶體接近於0
  • used記憶體接近總共記憶體
  • available記憶體(或者是free + buffers/cache)有足夠空間(比如說:總記憶體的20%以上)
  • swap used沒有發生變化

真正的記憶體不夠、你也許想調查原因的情形,警告標誌如下:

  • available記憶體(或者是free + buffers/cache)接近於0
  • swap used在增加或者波動
  • dmesg | grep oom-killer命令顯示OutOfMemory-killer程式正在執行

我如何驗證這些?

如果想了解更多細節和做實驗測試磁碟快取的影響,請看這個頁面。我做了少量的工作只是想讓你感激磁碟快取,而不是讓你測試你的硬體速度提升了幾個數量級。

Experiments and fun with the Linux disk cache

Hopefully you are now convinced that Linux didn't just eat your ram. Here are some interesting things you can do to learn how the disk cache works.

Effects of disk cache on application memory allocation

Since I've already promised that disk cache doesn't prevent applications from getting the memory they want, let's start with that. Here is a C app (munch.c) that gobbles up as much memory as it can, or to a specified limit:

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main(int argc, char** argv) {
    int max = -1;
    int mb = 0;
    char* buffer;

    if(argc > 1)
        max = atoi(argv[1]);

    while((buffer=malloc(1024*1024)) != NULL && mb != max) {
        memset(buffer, 0, 1024*1024);
        mb++;
        printf("Allocated %d MB\n", mb);
    }

    return 0;
}

Running out of memory isn't fun, but the OOM killer should end just this process and hopefully the rest will remain undisturbed. We'll definitely want to disable swap for this, or the app will gobble up that as well.

$ sudo swapoff -a

$ free -m

(note that your free output could be different, and have an 'available' column ins