Linux 面試經典:buff 和 cache 到底差在哪?從 vmstat 看懂 Page Cache 與 Buffer
buff 和 cache 都是拿記憶體來暫存資料,那它們到底差在哪?「我的 free 記憶體怎麼只剩一點點,是不是系統快掛了?」
這篇文章簡述 Linux 記憶體的機制,它們各自快取什麼、為什麼現代 kernel 上 buff 通常小得可憐,最後用一個 vmstat 的小實驗,實際讓 buff 和 cache 分別「動起來」。
Buffer 與 Cache
教科書式的定義:
- Buffer(緩衝區):暫存「正在搬運中」的資料。當資料在兩個速度不對等的裝置之間傳輸(例如應用程式寫入硬碟),資料不會直接落到目的地,而是先進入 buffer,讓 kernel 可以把零碎的寫入合併成較大的批次,一次性刷到磁碟上。這對循序 I/O 特別有效。
- Cache(快取):暫存「已經讀過、之後可能再用到」的資料。把常用的資料留一份在比較快的儲存層(RAM),下次要用時就不必再去慢速的磁碟撈一次。CPU cache、disk cache、filesystem cache 都是同一個精神。
一句話總結:buffer 著重協調資料傳輸,cache 著重保留資料以便重用 1。不過這只是通用概念,不能直接解讀成 Linux 的「buffer 只管寫、cache 只管讀」:一般檔案的 buffered read、buffered write 和 mmap() 都會經過 Page Cache;寫入的頁面會先成為 dirty page,再由 kernel 寫回儲存裝置 2 3。
在 Linux 上的實際意義:Page Cache vs Buffer Cache
上面的定義是通用概念,但落到 Linux 記憶體管理的 Buffers 和 Cached(也就是 /proc/meminfo 裡的兩個欄位),意義更具體 4:
| 欄位 | 快取的對象 | 典型場景 |
|---|---|---|
Cached(Page Cache) |
一般檔案的內容,也包含 tmpfs / shmem;不包含 SwapCached |
cat、grep、一般檔案的 buffered read / write |
Buffers(Buffer Cache) |
block device address space 裡的 raw disk blocks,以及部分檔案系統使用 buffer head 管理的磁碟上 metadata block | 對 /dev/sdX 做 buffered I/O、部分檔案系統的 journal / metadata I/O |
💡 記憶體統計有兩個容易忽略的細節
Cached不全是磁碟快取。 tmpfs / shmem 也包含在Cached裡;若只是想粗估 disk-backed file cache,可以看Cached - Shmem。在沒有 swap、且擁有者也沒有釋放頁面的情況下,這部分不能像 clean file cache 一樣直接丟棄 5。不是所有 filesystem metadata 都算進
Buffers。 只有部分檔案系統的磁碟上 metadata blocks 會使用 buffer head。VFS 的 inode object 與 dentry object 是獨立的記憶體內快取,通常計入Slab/SReclaimable6 4。
這裡有一個歷史脈絡值得知道:早期的 Page Cache 和 Buffer Cache 是兩套獨立快取;兩者後來合併,並在 Linux 2.4 時代移除檔案資料寫回所需的額外複本。現代 kernel 的 buffer cache 仍然存在,但 buffer head 會指向 Page Cache 裡的頁面 7 8。因此,Buffers 現在主要反映 raw disk blocks,而不是一般檔案內容;在多數工作負載中,它通常遠小於 Cached。
如果你今天在面試或除錯時被問到這題,更好的回答是:
Cached主要是 Page Cache(也包含 tmpfs / shmem),Buffers是 block device 的 raw disk blocks,以及部分檔案系統使用的 metadata blocks;inode / dentry object 則多半在 reclaimable slab。procps-ng 3.3.10 起,free預設用buff/cache彙總顯示,並加入available;目前版本的buff/cache實際是Buffers + Cached + SReclaimable9 10。
從 I/O 堆疊看 Page Cache 與 Buffer Cache 的位置
把整個 Linux I/O 路徑攤開來看,兩者的分工會更直觀 11:

Linux I/O 路徑:Page Cache 與 Buffer Cache 的位置
圖中的 filesystem metadata 指磁碟上的 metadata blocks;VFS 的 inode / dentry objects 則是前面提到的 slab caches。
- 走 filesystem 的路:應用程式
read()/write()一般檔案 → VFS → Page Cache。讀取命中(cache hit)就直接從 RAM 回傳;miss 或寫回 dirty page 時,才透過 filesystem 走到 Block Layer 與磁碟 2 - 走 raw block device 的路:對
/dev/sdX這類 block device 做一般 buffered I/O 時,不經過 mounted filesystem 的檔案對應邏輯,但仍會使用該 block device 自己的 page-cache mapping;這些頁面計入 Buffers 12 - 部分檔案系統也會用 buffer head 管理 journal 或磁碟上的 metadata blocks,但 VFS 的 inode / dentry object 是另一套 slab cache
- 兩條路最後都會匯入 Block Layer → Device Driver → 實體裝置。資料庫這類自己管理快取的應用,則可以用
O_DIRECT繞過 Page Cache;它仍會經過 filesystem 與 block layer,而不是直接呼叫硬體 2
用 vmstat 觀察 buff 與 cache
vmstat 是觀察系統記憶體、I/O 與 CPU 的基本工具。vmstat 1 5 表示每 1 秒取樣一次、共 5 次。第一列資料是自開機以來的平均值,後續各列才是每個取樣區間的數值 13:
$ vmstat 1 5
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
1 0 0 123456 7890 56789 0 0 100 200 300 400 10 5 80 5 0
0 1 0 120000 7895 56800 0 0 150 250 320 410 12 4 78 6 0
2 0 0 118500 7898 56810 0 0 180 220 330 420 9 6 82 3 0
1 0 0 116800 7902 56825 0 0 120 210 310 430 11 3 81 5 0
0 0 0 115000 7905 56835 0 0 140 230 300 390 13 4 77 6 0
跟這篇主題相關的欄位:
free:閒置記憶體buff:作為 buffer 使用的記憶體(對應/proc/meminfo的Buffers)cache:procps-ng 所彙整的 cache(目前為Cached + SReclaimable)bi/bo:每秒從 block device 讀入/寫出的 KiB;不受vmstat -S的顯示單位選項影響 13 14
上面的數字是示意資料。實際觀察時,若 bi / bo 持續有量,而 free 下降、buff 或 cache 上升,通常代表 kernel 正在把 block 或檔案資料留在記憶體裡;單看這個現象並不表示記憶體異常 15。
實驗:讓 buff 和 cache 分別動起來
光看定義還是抽象,直接做實驗最清楚。先清空快取,建立乾淨的基準:
# 把 dirty page 刷回磁碟,並清空 page cache、dentry、inode cache
$ sync
$ echo 3 | sudo tee /proc/sys/vm/drop_caches
drop_caches=3 會丟棄 clean page cache 與可回收的 slab objects(包括 dentry / inode cache);它不會丟掉 dirty objects,所以先執行 sync 能讓實驗結果更乾淨。這個介面適合測試與除錯,不建議當成日常「釋放記憶體」的手段,因為後續重建快取會產生額外 I/O 與 CPU 成本 16。
情境一:讀一般檔案 → cache 上升
先確認測試檔位於 disk-backed filesystem,而不是 tmpfs。開一個終端跑 vmstat -y 1(-y 省略自開機以來的第一列),另一個終端讀一個大檔案:
$ dd if=/var/tmp/bigfile of=/dev/null bs=1M status=progress
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
0 0 0 7452100 2120 98500 0 0 0 0 120 210 1 0 99 0 0
1 0 0 6890200 2135 652800 0 0 524288 0 850 1600 2 12 70 16 0
1 0 0 6320400 2150 1214500 0 0 524288 0 860 1620 1 13 68 18 0
檔案內容進的是 Page Cache,所以這組示意輸出裡 cache 每秒增加約 500 MiB,buff 幾乎不動。實際增幅會受檔案大小、讀取速度、既有快取與其他系統活動影響。
情境二:直接讀 raw block device → buff 上升
先重新執行前面的 sync 與 drop_caches,再用 lsblk 確認裝置名稱,並把下列 /dev/sdX 換成實際裝置。這個命令只讀取裝置並丟到 /dev/null;不要把 if / of 寫反,也不要加上 iflag=direct,否則會繞過想觀察的 cache:
$ sudo dd if=/dev/sdX of=/dev/null bs=1M count=1024 status=progress
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r b swpd free buff cache si so bi bo in cs us sy id wa st
0 0 0 7450300 2150 99200 0 0 0 0 115 200 1 0 99 0 0
1 0 0 6980100 471300 99800 0 0 460800 0 830 1550 1 11 71 17 0
1 0 0 6420500 1023800 100300 0 0 524288 0 855 1590 2 12 69 17 0
這次對 block device 做 buffered read,資料進入該裝置的 page-cache mapping,而 /proc/meminfo 把這些頁面列在 Buffers,所以換成 buff 明顯上升、cache 幾乎不動 12。
兩個實驗對照,buff 和 cache 的分工一目了然:一般檔案內容主要反映在 cache,block device mapping 裡的 raw blocks 反映在 buff。實驗數值不必與範例完全相同;背景服務、檔案系統和 kernel 版本都可能使其他欄位同時變動。
常見誤解:free 很低不是壞事
最後回頭解決那個常見的焦慮。Linux 會利用閒置 RAM 做快取,所以 free 很低本身不是故障。當應用程式需要記憶體時,clean file cache 與一部分 reclaimable slab 可以被回收;dirty page 要先寫回,正在使用的 slab 或沒有 swap 可退的 shmem 則不一定能立即回收 4 10。
判斷記憶體是否吃緊,別只看 free:
- 看
free指令輸出的available欄位:它估算在不進行 swap 的情況下,還有多少記憶體可供新應用程式使用;計算時會考慮 page cache、reclaimable slab 與 zone low watermarks 4 - 看
vmstat的si/so:持續的 swap in / out 是記憶體壓力的重要訊號;只看到 swap 已使用一些空間,不代表系統此刻正在 thrashing 17
總結
- 一般概念上,buffer 著重協調資料傳輸,cache 著重保留可重用資料;這不等於 Linux 的「寫 vs 讀」
- Linux 的
Cached主要反映 Page Cache,也包含 tmpfs / shmem;一般檔案的 buffered read 與 write 都會經過它 Buffers主要是 block device mapping 的 raw disk blocks,以及部分檔案系統使用的 metadata blocks;inode / dentry object 通常在 reclaimable slab- Page Cache 與 Buffer Cache 在 Linux 2.4 時代完成統一,現代系統的主要檔案快取是 Page Cache
- 用
vmstat 1搭配「讀檔案 vs 讀 raw device」的實驗,可以清楚看到cache與buff分別上升 free很低不等於記憶體不足,需進一步確認available與 swap 活動
參考資料
-
Stack Overflow — What is the difference between buffer and cache memory in Linux? ↩
-
Linux kernel documentation — The /proc Filesystem: /proc/meminfo ↩ ↩2 ↩3 ↩4
-
Server Fault — In Linux, what is the difference between “buffers” and “cache” reported by the free command? ↩
-
Linux kernel documentation — Overview of the Linux Virtual File System ↩
-
Unix & Linux Stack Exchange — 30% of RAM is “buffers”. What is it? ↩
-
Linux kernel source — buffered block-device I/O and page-cache mapping / Buffers comes from nr_blockdev_pages() / nr_blockdev_pages() implementation ↩ ↩2
-
procps-ng source — vmstat uses MEMINFO_MEM_CACHED_ALL / Cached + SReclaimable ↩
-
Fedora Magazine — System insights with command-line tools: free and vmstat ↩