應(yīng)用程序產(chǎn)生Page Cache的邏輯示意圖
紅色的地方就是 Page Cache,很明顯,Page Cache是內(nèi)核管理的內(nèi)存,也就是說(shuō),它屬于內(nèi)核不屬于用戶。
如何觀察 Page Cache? 在 linux 上直接查看 Page Cache 的方式有很多,包括 /proc/meminfo、free 、/proc/vmstat 命令等,它們的內(nèi)容其實(shí)是一致的。拿 /proc/meminfo 命令舉例看一下:
$ cat /proc/meminfo
...
Buffers: 1224 kB
Cached: 111472 kB
SwapCached: 36364 kB
Active: 6224232 kB
Inactive: 979432 kB
Active(anon): 6173036 kB
Inactive(anon): 927932 kB
Active(file): 51196 kB
Inactive(file): 51500 kB
...
Shmem: 10000 kB
...
SReclaimable: 43532 kB
根據(jù)上面的數(shù)據(jù),你可以簡(jiǎn)單得出這樣的公式(等式兩邊之和都是 112696 KB):
Buffers + Cached + SwapCached = Active(file) + Inactive(file) + Shmem + SwapCached
那么等式兩邊的內(nèi)容就是我們平時(shí)說(shuō)的 Page Cache。請(qǐng)注意你沒(méi)有看錯(cuò),兩邊都有Swap Cached,之所以要把它放在等式里,就是說(shuō)它也是 Page Cache 的一部分。等式右邊這些項(xiàng)把 Buffers 和 Cached 做了一下細(xì)分,分為了 Active(file),Inactive(file) 和 Shmem,因?yàn)?Buffers 更加依賴于內(nèi)核實(shí)現(xiàn),在不同內(nèi)核版本中它的含義可能有些不一致,而等式右邊和應(yīng)用程序的關(guān)系更加直接,所以我們從等式右邊來(lái)分析.
在 Page Cache 中,Active(file)+Inactive(file) 是 File-backed page(與文件對(duì)應(yīng)的內(nèi)存頁(yè)),是你最需要關(guān)注的部分。因?yàn)槟闫綍r(shí)用的 mmap() 內(nèi)存映射方式和 buffered I/O來(lái)消耗的內(nèi)存就屬于這部分,最重要的是,這部分在真實(shí)的生產(chǎn)環(huán)境上也最容易產(chǎn)生問(wèn)題,我們?cè)诮酉聛?lái)的課程案例篇會(huì)重點(diǎn)分析它。
而 SwapCached 是在打開(kāi)了 Swap 分區(qū)后,把 Inactive(anon)+Active(anon) 這兩項(xiàng)里的匿名頁(yè)給交換到磁盤(pán)(swap out),然后再讀入到內(nèi)存(swap in)后分配的內(nèi)存。由于讀入到內(nèi)存后原來(lái)的 Swap File 還在,所以 SwapCached 也可以認(rèn)為是 File-backed page,即屬于 Page Cache。這樣做的目的也是為了減少 I/O。
通過(guò)下面簡(jiǎn)單的示意圖明白 SwapCached 是怎么產(chǎn)生的:
SwapCached 只在 Swap 分區(qū)打開(kāi)的情況下才會(huì)有,而我建議你在生產(chǎn)環(huán)境中關(guān)閉 Swap 分區(qū),因?yàn)?Swap 過(guò)程產(chǎn)生的 I/O 會(huì)很容易引起性能抖動(dòng)。

Page Cache 中的 Shmem 是指匿名共享映射這種方式分配的內(nèi)存(free 命令中 shared 這一項(xiàng)),比如 tmpfs(臨時(shí)文件系統(tǒng)),這部分在真實(shí)的生產(chǎn)環(huán)境中產(chǎn)生的問(wèn)題比較少。
free 命令中的 buff/cache 究竟是指什么呢?
free 命令也是通過(guò)解析 /proc/meminfo 得出這些統(tǒng)計(jì)數(shù)據(jù)的,這些都可以通過(guò) free 工具的源碼來(lái)找到。free 命令的源碼是開(kāi)源,你可以去看下 procfs里的 free.c 文件,源碼是最直接的理解方式,它會(huì)加深你對(duì) free 命令的理解。
$ free -k
total used free shared buff/cache availabl
Mem: 7926580 7277960 492392 10000 156228 43068
Swap: 8224764 380748 7844016
通過(guò) procfs 源碼里面的proc/sysinfo.c這個(gè)文件,你可以發(fā)現(xiàn) buff/cache 包括下面這幾項(xiàng):
buff/cache = Buffers + Cached + SReclaimable
通過(guò)前面的數(shù)據(jù)我們也可以驗(yàn)證這個(gè)公式: 1224 + 111472 + 43532 的和是 156228。
free 命令中的 buff/cache 是由 Buffers、Cached 和 SReclaimable 這三項(xiàng)組成的,它強(qiáng)調(diào)的是內(nèi)存的可回收性,也就是說(shuō),可以被回收的內(nèi)存會(huì)統(tǒng)計(jì)在這一項(xiàng)。
SReclaimable 是指可以被回收的內(nèi)核內(nèi)存,包括 dentry 和 inode 等。
掌握了 Page Cache 具體由哪些部分構(gòu)成之后,在它引發(fā)一些問(wèn)題時(shí),你就能夠知道需要去觀察什么。比如說(shuō),應(yīng)用本身消耗內(nèi)存(RSS)不多的情況下,整個(gè)系統(tǒng)的內(nèi)存使用率還是很高,那不妨去排查下是不是 Shmem(共享內(nèi)存) 消耗了太多內(nèi)存導(dǎo)致的。
為什么需要 Page Cache?
第一張圖你其實(shí)已經(jīng)可以直觀地看到,標(biāo)準(zhǔn) I/O 和內(nèi)存映射會(huì)先把數(shù)據(jù)寫(xiě)入到 Page Cache,這樣做會(huì)通過(guò)減少 I/O 次數(shù)來(lái)提升讀寫(xiě)效率。
看一個(gè)具體的例子。首先,我們來(lái)生成一個(gè) 1G 大小的新文件,然后把 Page Cache 清空,確保文件內(nèi)容不在內(nèi)存中,以此來(lái)比較第一次讀文件和第二次讀文件耗時(shí)的差異。具體的流程如下。
- 先生成一個(gè) 1G 的文件:
dd if = /dev/zero of = /home/test/dd.outbs = 4096 count = ((1024*256))
2 . 清空 Page Cache,需要先執(zhí)行一下 sync 來(lái)將臟頁(yè)同步到磁盤(pán)再去 drop cache。
sync && echo 3 > /proc/sys/vm/drop_caches
3 . 第一次讀取文件的耗時(shí)如下:
$ time cat /home/test/dd.out &> /dev/null
real 0m5.733s
user 0m0.003s
sys 0m0.213s
再次讀取文件的耗時(shí)如下:
$ time cat /home/test/dd.out &> /dev/null
real 0m0.132s
user 0m0.001s
sys 0m0.130s
第二次讀取文件的耗時(shí)遠(yuǎn)小于第一次的耗時(shí),這是因?yàn)榈谝淮问菑拇疟P(pán)來(lái)讀取的內(nèi)容,磁盤(pán) I/O 是比較耗時(shí)的,而第二次讀取的時(shí)候由于文件內(nèi)容已經(jīng)在第一次讀取時(shí)被讀到內(nèi)存了,所以是直接從內(nèi)存讀取的數(shù)據(jù),內(nèi)存相比磁盤(pán)速度是快很多的。這就是 Page Cache 存在的意義:減少 I/O,提升應(yīng)用的 I/O 速度。