應用程序產(chǎn)生Page Cache的邏輯示意圖
紅色的地方就是 Page Cache,很明顯,Page Cache是內(nèi)核管理的內(nèi)存,也就是說,它屬于內(nèi)核不屬于用戶。
如何觀察 Page Cache? 在 linux 上直接查看 Page Cache 的方式有很多,包括 /proc/meminfo、free 、/proc/vmstat 命令等,它們的內(nèi)容其實是一致的。拿 /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ù),你可以簡單得出這樣的公式(等式兩邊之和都是 112696 KB):
Buffers + Cached + SwapCached = Active(file) + Inactive(file) + Shmem + SwapCached
那么等式兩邊的內(nèi)容就是我們平時說的 Page Cache。請注意你沒有看錯,兩邊都有Swap Cached,之所以要把它放在等式里,就是說它也是 Page Cache 的一部分。等式右邊這些項把 Buffers 和 Cached 做了一下細分,分為了 Active(file),Inactive(file) 和 Shmem,因為 Buffers 更加依賴于內(nèi)核實現(xiàn),在不同內(nèi)核版本中它的含義可能有些不一致,而等式右邊和應用程序的關(guān)系更加直接,所以我們從等式右邊來分析.
在 Page Cache 中,Active(file)+Inactive(file) 是 File-backed page(與文件對應的內(nèi)存頁),是你最需要關(guān)注的部分。因為你平時用的 mmap() 內(nèi)存映射方式和 buffered I/O來消耗的內(nèi)存就屬于這部分,最重要的是,這部分在真實的生產(chǎn)環(huán)境上也最容易產(chǎn)生問題,我們在接下來的課程案例篇會重點分析它。
而 SwapCached 是在打開了 Swap 分區(qū)后,把 Inactive(anon)+Active(anon) 這兩項里的匿名頁給交換到磁盤(swap out),然后再讀入到內(nèi)存(swap in)后分配的內(nèi)存。由于讀入到內(nèi)存后原來的 Swap File 還在,所以 SwapCached 也可以認為是 File-backed page,即屬于 Page Cache。這樣做的目的也是為了減少 I/O。
通過下面簡單的示意圖明白 SwapCached 是怎么產(chǎn)生的:
SwapCached 只在 Swap 分區(qū)打開的情況下才會有,而我建議你在生產(chǎn)環(huán)境中關(guān)閉 Swap 分區(qū),因為 Swap 過程產(chǎn)生的 I/O 會很容易引起性能抖動。
Page Cache 中的 Shmem 是指匿名共享映射這種方式分配的內(nèi)存(free 命令中 shared 這一項),比如 tmpfs(臨時文件系統(tǒng)),這部分在真實的生產(chǎn)環(huán)境中產(chǎn)生的問題比較少。
free 命令中的 buff/cache 究竟是指什么呢?
free 命令也是通過解析 /proc/meminfo 得出這些統(tǒng)計數(shù)據(jù)的,這些都可以通過 free 工具的源碼來找到。free 命令的源碼是開源,你可以去看下 procfs里的 free.c 文件,源碼是最直接的理解方式,它會加深你對 free 命令的理解。
$ free -k
total used free shared buff/cache availabl
Mem: 7926580 7277960 492392 10000 156228 43068
Swap: 8224764 380748 7844016
通過 procfs 源碼里面的proc/sysinfo.c這個文件,你可以發(fā)現(xiàn) buff/cache 包括下面這幾項:
buff/cache = Buffers + Cached + SReclaimable
通過前面的數(shù)據(jù)我們也可以驗證這個公式: 1224 + 111472 + 43532 的和是 156228。
free 命令中的 buff/cache 是由 Buffers、Cached 和 SReclaimable 這三項組成的,它強調(diào)的是內(nèi)存的可回收性,也就是說,可以被回收的內(nèi)存會統(tǒng)計在這一項。
SReclaimable 是指可以被回收的內(nèi)核內(nèi)存,包括 dentry 和 inode 等。
掌握了 Page Cache 具體由哪些部分構(gòu)成之后,在它引發(fā)一些問題時,你就能夠知道需要去觀察什么。比如說,應用本身消耗內(nèi)存(RSS)不多的情況下,整個系統(tǒng)的內(nèi)存使用率還是很高,那不妨去排查下是不是 Shmem(共享內(nèi)存) 消耗了太多內(nèi)存導致的。
為什么需要 Page Cache?
第一張圖你其實已經(jīng)可以直觀地看到,標準 I/O 和內(nèi)存映射會先把數(shù)據(jù)寫入到 Page Cache,這樣做會通過減少 I/O 次數(shù)來提升讀寫效率。
看一個具體的例子。首先,我們來生成一個 1G 大小的新文件,然后把 Page Cache 清空,確保文件內(nèi)容不在內(nèi)存中,以此來比較第一次讀文件和第二次讀文件耗時的差異。具體的流程如下。
- 先生成一個 1G 的文件:
dd if = /dev/zero of = /home/test/dd.outbs = 4096 count = ((1024*256))
2 . 清空 Page Cache,需要先執(zhí)行一下 sync 來將臟頁同步到磁盤再去 drop cache。
sync && echo 3 > /proc/sys/vm/drop_caches
3 . 第一次讀取文件的耗時如下:
$ time cat /home/test/dd.out &> /dev/null
real 0m5.733s
user 0m0.003s
sys 0m0.213s
再次讀取文件的耗時如下:
$ time cat /home/test/dd.out &> /dev/null
real 0m0.132s
user 0m0.001s
sys 0m0.130s
第二次讀取文件的耗時遠小于第一次的耗時,這是因為第一次是從磁盤來讀取的內(nèi)容,磁盤 I/O 是比較耗時的,而第二次讀取的時候由于文件內(nèi)容已經(jīng)在第一次讀取時被讀到內(nèi)存了,所以是直接從內(nèi)存讀取的數(shù)據(jù),內(nèi)存相比磁盤速度是快很多的。這就是 Page Cache 存在的意義:減少 I/O,提升應用的 I/O 速度。






