用途:文件/块设备I/O加速,占用大量物理内存。
现象:读/写大文件,free 命令 buff/cache
显著增长。
实战命令:
# 查看 buff/cache 变化
free -h
# 查看详细内存类型分布
cat /proc/meminfo | grep -E 'Cached|Buffers'
典型代码(读文件触发 Page Cache):
// 文件内容被 Page Cache 缓存
FILE *fp = fopen("/tmp/largefile", "r");
char buf[4096];
while (fread(buf, 1, sizeof(buf), fp) > 0) { /* 触发页缓存 */ }
fclose(fp);
用途:内核频繁分配的小对象(如 task_struct、inode、dentry)的高效缓存。
典型现象:dentry/inode 缓存高峰时,占用大量物理内存。
内核代码片段(内核对象 slab 分配):
struct task_struct *tsk = kmem_cache_alloc(task_struct_cachep, GFP_KERNEL);
// ... do work ...
kmem_cache_free(task_struct_cachep, tsk);
实用命令:
# slabtop 工具查看 Slab/Slub cache 占用
slabtop
用途:应用程序分配的内存,最终通过系统调用由内核分配物理页。
示例代码:
char *buf = malloc(1024*1024); // 用户空间分配
strcpy(buf, "hello world");
free(buf);
作用:操作系统用页(Page,通常4K)为单位管理物理内存。
核心流程(伪代码):
// 进程访问虚拟地址,内核页表转换
physical_page = mmu_lookup(virtual_address, current->mm->page_table);
[ 物理内存 RAM ]
+-----------------------------------+
| Page0 | Page1 | ... | PageN |
+-----------------------------------+
↓ ↓ ↓
+------+ +--------+ +---------+
| Slab | | Page | | 用户堆 |
|Cache | | Cache | | (malloc)|
+------+ +--------+ +---------+
(内核对象) (文件缓存) (应用数据)
// 伪代码:读文件,未命中 page cache,则分配新页
struct page *page = find_get_page(mapping, index);
if (!page) {
page = alloc_page(GFP_KERNEL); // 分配物理页
add_to_page_cache_lru(page, mapping, index, GFP_KERNEL);
// ...读取磁盘内容到page...
}
# free/top 等都能直观看到 buff/cache
free -h
top
# /proc/meminfo 详细统计(关键行)
cat /proc/meminfo | grep -E 'Buffers|Cached|Slab'
Buffers
、Cached
、Slab
分别对应块缓存、页缓存、slab对象池缓存。编写应用,持续读写大文件,观察 Page Cache 激增
FILE *fp = fopen("/tmp/bigfile", "w");
for (int i = 0; i < 1024*1024; ++i)
fwrite("abcdefghij", 1, 10, fp);
fclose(fp);
// 此时 free -h 可见 buff/cache 大增
手动释放缓存页(慎用,示例)
# 释放Page Cache
sync; echo 1 > /proc/sys/vm/drop_caches
# 释放Page+inode/dentry
sync; echo 3 > /proc/sys/vm/drop_caches
触发 inode/dentry 大量分配
find /
、ls -lR /
这类操作会暴增 Slab Cache。slabtop
实时查看对象池缓存波动。brk/mmap
→ 页表 → 物理页分配slabtop
/free
命令和实际代码实验观察)“缓存其实就是物理页,分页机制是根本。代码验证多实验,现象理解才深刻。”