buffer和cache

Linux Buffer 与 Cache 原理及观测完整文档

1. 文档目标

本文档面向有一定 Linux 运维、内核或性能调优经验的工程人员,系统性说明:

  • Buffer 与 Cache 的内核语义与历史背景

  • 二者在现代 Linux 内核中的统一实现方式

  • 内存回收、脏页与写回机制

  • 工程级观测方法(free / meminfo / vmstat / eBPF 工具)

  • 典型性能问题定位路径

目标不是概念普及,而是帮助在真实系统中正确判断内存与 I/O 行为


2. Linux 内存设计总览

Linux 的核心内存设计原则是:

空闲内存是浪费的内存。

因此:

  • 内存会被尽可能用于缓存

  • Cache 与 Buffer 属于可回收内存

  • 内存紧张时,内核会自动回收它们

在现代内核中,Cache / Buffer / Slab 均参与统一的回收体系(LRU + reclaim)。


3. Buffer 的定义与实现

3.1 逻辑定义

Buffer(Buffer Cache) 用于缓存:

  • 块设备(block device)上的数据块

  • 文件系统元数据(inode、superblock、bitmap)

  • Journal / raw block I/O

它的关注点是:

  • “块”

  • “设备”

  • “文件系统结构”

3.2 内核实现要点

  • 实际内存载体仍然是 struct page

  • 通过 struct buffer_head 描述 page 中的 block

  • buffer 并不拥有独立内存池

关键结论:

Buffer 只是 Page Cache 的一种使用方式


4. Cache 的定义与实现

4.1 逻辑定义

通常所说的 Cache 指:

  • Page Cache

  • 文件内容缓存(file-backed pages)

服务对象:

  • 普通文件

  • 可执行文件

  • 动态库

  • mmap 文件

4.2 读写路径

  • read():

    • 命中 → 直接内存拷贝

    • 未命中 → 磁盘 I/O → 填充 page cache

  • write():

    • 写入 page cache

    • 标记 dirty

    • 延迟写回磁盘

4.3 mmap 行为

  • mmap 文件直接映射 page cache

  • 修改 mmap 区域等价于修改 page cache

  • 回写由内核统一调度


5. Buffer 与 Cache 的关系

维度BufferCache
面向对象 块设备 文件
使用场景 元数据 / raw I/O 文件内容
是否独立内存
是否可回收
内核载体 page + buffer_head page

核心结论:

二者在物理内存层面没有边界,仅是统计与语义区分。


6. 低阶内存与高阶内存(LowMem / HighMem)

6.1 背景与历史意义

低阶内存与高阶内存的划分,源自 32 位 Linux 内核的虚拟地址空间限制,但其思想对理解现代内核内存布局、ZONE 划分、内存回收路径仍然非常重要。

在 32 位系统中:

  • 内核虚拟地址空间通常只有 1GB(3G/1G 模型)

  • 并非所有物理内存都能被内核永久映射

因此引入了 High Memory(高端内存) 的概念。


6.2 低阶内存(Low Memory)

低阶内存指:

  • 始终被内核线性映射

  • 可以直接通过虚拟地址访问

在 x86 32 位中通常包括:

  • ZONE_DMA

  • ZONE_NORMAL

特性:

  • 内核代码、内核数据结构必须位于低阶内存

  • slab、page cache、buffer cache 的核心元数据依赖低阶内存

  • 低阶内存耗尽会直接导致系统不稳定


6.3 高阶内存(High Memory)

高阶内存指:

  • 不被永久映射到内核地址空间

  • 需要通过临时映射(kmap / kmap_atomic)访问

在 x86 32 位中:

  • ZONE_HIGHMEM

特点:

  • 主要用于存放用户态数据页

  • Page Cache 的数据页大量来自高阶内存

  • 访问成本更高


6.4 HighMem 与 Buffer / Cache 的关系

关键点:

  • Page Cache 的 数据页 可以位于 HighMem

  • Page Cache 的 元数据(struct page、radix tree)必须位于 LowMem

  • Buffer_head 本身位于 LowMem

因此会出现经典现象:

HighMem 充足,但 LowMem 耗尽,系统仍然 OOM


6.5 低阶内存耗尽的典型症状

  • dmesg 中出现:

    • "Low memory"

    • "Out of memory"

  • slabtop 显示 slab 对象异常增大

  • Page Cache 很大,但内核分配失败


6.6 观测低阶 / 高阶内存

6.6.1 /proc/meminfo

关键字段:

  • LowTotal / LowFree

  • HighTotal / HighFree

  • DMA / DMA32 / Normal

6.6.2 /proc/zoneinfo

用于精确分析各 ZONE:

  • free pages

  • watermarks

  • reclaim 行为


6.7 在 64 位系统中的变化

在 64 位 Linux 中:

  • 地址空间充足

  • 不再区分传统意义上的 HighMem

  • ZONE_HIGHMEM 通常不存在

但以下问题仍然存在:

  • ZONE_DMA / DMA32 限制

  • 内核虚拟地址碎片

  • 高阶页(order > 0)分配失败


7. 脏页(Dirty Page)与写回机制

6.1 Dirty Page

  • 被修改但尚未写入磁盘的 page

  • 包含 buffer 与 cache 产生的脏页

6.2 写回控制参数

  • vm.dirty_ratio

  • vm.dirty_background_ratio

  • vm.dirty_expire_centisecs

  • vm.dirty_writeback_centisecs

6.3 回收优先级(简化)

  1. Page cache(clean)

  2. Page cache(dirty → writeback)

  3. Slab reclaimable

  4. Swap


7. 基础观测工具

7.1 free

  • buff/cache:buffer + cache

  • available:判断是否内存紧张的关键指标

7.2 /proc/meminfo

关键字段:

  • Buffers

  • Cached

  • SReclaimable

  • Dirty

  • Writeback

这是最权威的数据来源。

7.3 vmstat

重点关注:

  • si / so(swap)

  • wa(I/O wait)

  • kswapd 活跃度


8. cachetop:Page Cache 命中率观测

8.1 工具定位

cachetop 是基于 eBPF 的诊断工具,用于统计:

  • Page Cache 命中(hits)

  • 未命中(misses)

  • 脏页产生(dirties)

  • 读命中率(READ_HIT%)

它回答的问题是:

Cache 是否真的提升了性能。

8.2 统计原理

通过 hook 内核路径:

  • mark_page_accessed

  • add_to_page_cache_lru

  • account_page_dirtied

因此反映真实 I/O 行为。

8.3 工程判断经验

READ_HIT%判断
> 99% 非常健康
95–99% 正常
90–95% 需关注
< 90% 明显 I/O 风险

9. cachestat / filetop / vfsstat

9.1 cachestat

  • 系统级 cache 行为

  • 判断整体 cache 效率

9.2 filetop

  • 文件维度读写统计

  • 定位 cache 污染源

9.3 vfsstat

  • VFS 层调用统计

  • 辅助判断 metadata / buffer 压力


10. Buffer 行为的工程观测

Buffer 通常隐藏在:

  • 文件系统 metadata

  • journal 写入

表现为:

  • Buffers 偏高

  • bi/bo 增大

  • journal I/O 活跃

需结合:

  • /proc/meminfo

  • iostat -x


11. 典型问题与定位路径

11.1 Cache 很大但性能差

  • free:cache 大

  • vmstat:wa 高

  • cachetop:READ_HIT% 低

结论:

  • Cache 被顺序 I/O 冲刷

  • 工作集超出内存

11.2 单进程污染 Cache

  • cachetop:单 PID miss 极高

  • filetop:大文件顺序读

对策:

  • O_DIRECT

  • posix_fadvise(DONTNEED)


12. 常见误区澄清

  • Cache 多 ≠ 内存不足

  • free 少 ≠ 内存压力

  • Buffer/Cache 不会抢应用内存


13. 工程级总结

  1. Buffer 与 Cache 本质统一于 Page Cache

  2. 关键不是“占用多少”,而是“命中率如何”

  3. cachetop 是判断 cache 是否有效的核心工具

  4. 真正的内存压力指标是:

    • available

    • swap

    • kswapd

    • I/O wait


14. /proc 与 cgroup 视角的内存观测(核心补充)

本章节从 内核真实数据源 的角度,补充说明内存、cache、buffer、slab 在 procfs 与 cgroup 中的表现与差异。这是生产排障中不可缺失的一层。


14.1 MEMINFO:/proc/meminfo(全局内存事实源)

/proc/meminfo 是 Linux 内存统计的唯一权威来源,free/top/ps 均基于它派生。

14.1.1 与 Cache / Buffer / Slab 直接相关字段

  • MemTotal / MemFree

  • Buffers

  • Cached

  • SReclaimable

  • Slab

  • Dirty / Writeback

  • LowTotal / LowFree(32 位或开启 HighMem)

  • HighTotal / HighFree

关系说明:

  • Cached:文件页 page cache(不含 swap cache)

  • Buffers:block buffer(metadata / raw I/O)

  • Slab = SReclaimable + SUnreclaim

  • available = MemFree + 可回收 cache + SReclaimable

关键工程结论:

判断内存是否紧张,永远不要只看 MemFree。


14.2 SLABINFO:/proc/slabinfo(内核对象内存)

Slab 是 低阶内存的主要消耗者之一,在 cache / buffer / VFS / 网络栈 中无处不在。

14.2.1 slab 的构成

  • inode_cache

  • dentry

  • buffer_head

  • kmalloc-*

  • task_struct

这些对象:

  • 全部位于 LowMem

  • 大量存在会直接挤压 page cache 元数据空间

14.2.2 slabinfo 的工程价值

  • 发现 slab 泄漏

  • 解释 LowMem 耗尽但 HighMem 充足的问题

  • 定位 VFS / 网络 / buffer_head 异常增长

通常配合:

  • slabtop

  • /proc/meminfo 中的 Slab / SReclaimable


14.3 CGROUP V1:/sys/fs/cgroup/memory

在 cgroup v1 中,page cache 计入 memory.limit,这是大量“容器内存误判”的根源。

14.3.1 关键文件

  • memory.usage_in_bytes

  • memory.limit_in_bytes

  • memory.stat

memory.stat 中重要字段:

  • cache

  • rss

  • mapped_file

  • inactive_file / active_file

  • inactive_anon / active_anon

工程结论:

  • cache 与 rss 共享内存上限

  • cache 压缩会直接影响应用性能

  • drop_caches 在容器内可能被误用


14.4 CGROUP ROOT:/sys/fs/cgroup(v2 统一层级)

cgroup v2 采用 统一内存控制模型,但 cache 统计更加复杂。

14.4.1 关键路径

  • memory.current

  • memory.max

  • memory.stat

  • memory.events

memory.stat 中:

  • file

  • anon

  • slab

  • slab_reclaimable

  • slab_unreclaimable

关键区别:

  • slab 被显式计入 cgroup

  • file cache 与 anon 明确区分

  • OOM 与 reclaim 事件可观测


14.5 Slab 在 cgroup 中的表现

  • cgroup v1:slab 不完全计入(历史问题)

  • cgroup v2:slab 明确计入 memory.max

工程影响:

  • 大量 dentry / inode 会导致容器 OOM

  • 但 free/top 在 host 上看似正常


14.6 常见“内存看不懂”的真实原因

  1. meminfo 看的是 全局

  2. cgroup 看的是 配额内

  3. slab 占用的是 LowMem

  4. cache 在 cgroup 中是 受限资源


15. 适用场景

  • 性能压测分析

  • I/O 瓶颈定位

  • 数据库 / 大数据 / 容器环境

  • 内核行为理解与调优

posted on 2026-01-15 17:55  吃草的青蛙  阅读(1)  评论(0)    收藏  举报

导航