一、什么是脏页(Dirty Page)
定义:
脏页是指 内存中被修改过但还没写回磁盘的页(page)。
当写入文件(如 write() 系统调用)时,数据通常不会立刻写入磁盘,而是:
- 内核先把数据写入 页缓存(Page Cache);
- 这块缓存页被标记为 “脏”(dirty);
- 后台的 写回(writeback)线程 在合适的时机(比如页太多、时间到、内存压力大)将脏页写入磁盘;
- 写入完成后,页标记为 干净(clean)。
这种机制提高了性能 —— 避免每次 I/O 都直接写磁盘。
二、脏页的典型来源
| 来源 | 说明 |
|---|---|
| 文件写操作 | 用户态程序 write()、fwrite() 等 |
| 内核缓存写入 | 日志系统、数据库缓冲区 |
| mmap 映射写 | 通过 mmap() 映射文件后直接修改内存 |
| 文件系统元数据更新 | 文件创建、删除、权限修改等 |
三、脏页相关内核参数(重点)
cat /proc/sys/vm/dirty_ratio
cat /proc/sys/vm/dirty_background_ratio
cat /proc/sys/vm/dirty_expire_centisecs
cat /proc/sys/vm/dirty_writeback_centisecs
cat /proc/sys/vm/dirty_background_bytes
cat /proc/sys/vm/dirty_bytes
dirty_ratio
- 含义:系统中可用内存的百分比,当脏页占比超过该值时,进程自身的写操作会被阻塞,直到脏页写回部分。
- 默认值:20
示例:
内存 8GB → 超过 1.6GB 脏页时,用户写操作被阻塞。
dirty_background_ratio
- 含义:系统中可用内存的百分比,当脏页占比超过这个值时,内核后台线程(
flush)开始异步写回。 - 默认值:10
示例:
内存总量 = 8GB
dirty_background_ratio = 10
→ 当脏页超过 0.8GB 时,后台线程开始写回。
dirty_expire_centisecs
- 含义:脏页在内存中存在超过此时间后(单位为百分之一秒),即使未达到比例,也会被写回。
- 默认值:3000(即 30 秒)
- 影响:控制数据写回延迟,值越大缓存越久,但断电丢数据风险更高。
dirty_writeback_centisecs
- 含义:后台线程写回任务的执行周期。
- 默认值:500(即 5 秒)
- 意思:每隔 5 秒,内核会扫描脏页并尝试写回。
dirty_bytes与dirty_background_bytes
- 和上面两个类似,但以 字节数 而不是百分比指定。
- 如果设置了这两个参数,
ratio参数会被忽略。
示例:
echo 67108864 > /proc/sys/vm/dirty_bytes # 64MB
echo 33554432 > /proc/sys/vm/dirty_background_bytes # 32MB
四、脏页的状态查看
# 1. 查看整体脏页信息
cat /proc/meminfo | grep -E 'Dirty|Writeback'
# 输出示例:
# Dirty: 4096 kB 当前系统脏页数
# Writeback: 512 kB 正在写回的页数
# 2. 查看详细写回状态
cat /proc/vmstat | grep -E 'dirty|writeback'
# 3. 持续写文件的程序
dd if=/dev/zero of=/tmp/testfile bs=1M count=2048
五、调优
| 现象 | 可能原因 | 调优方向 |
|---|---|---|
| 系统卡顿、I/O 等待高 | 脏页过多写回阻塞 | 降低 dirty_ratio |
| 写入性能差 | 写回频繁、后台线程压力大 | 提高 dirty_background_ratio |
| 数据丢失风险高 | 写回间隔太长 | 降低 dirty_expire_centisecs |
| 嵌入式设备断电丢数据 | 缓存写回不及时 | 降低比例、手动 fsync() |
测试示例:
# 方法1:添加oflag=sync参数(但这会强制同步写入,反而减少脏页)
# 不推荐:dd if=/dev/zero of=/mnt/data/nav_manager_test.log bs=1M count=10000 oflag=sync
# 方法2:分批次写入并保持文件打开
for i in {1..10}; do
dd if=/dev/zero of=/mnt/data/nav_manager_test.log bs=1M count=1000 oflag=append conv=notrunc
sleep 1 # 短暂暂停,让脏页有时间积累
echo "已完成第 $i 批次写入,当前脏页: $(grep Dirty: /proc/meminfo)"
done
# 方法3:配合其他命令监控和维持脏页
# 在一个终端运行dd命令
# 在另一个终端运行以下命令监控脏页
echo 100 > /proc/sys/vm/dirty_ratio # 增加脏页比例阈值
echo 50 > /proc/sys/vm/dirty_background_ratio
echo 360000 > /proc/sys/vm/dirty_writeback_centisecs # 延长脏页刷新间隔
watch -n 1 "grep Dirty: /proc/meminfo"
# 实时监控脏页变化情况
watch grep Dirty: /proc/meminfo
# 当前参数分析
dirty_expire_centisecs = 1000:# 脏页在内存中停留的最长时间为10秒(1000/100)
dirty_ratio = 1:# 当脏页占系统内存比例超过1%时,所有进程会被强制将脏页写回磁盘(这个值非常低,容易触发同步写入)
dirty_background_ratio = 30:# 当脏页占系统内存比例超过30%时,后台进程开始将脏页写回磁盘
# 要增加脏页内存,需要:
1. 增加dirty_ratio值,减少系统强制同步写入的频率
2. 可以考虑增加dirty_expire_centisecs值,让脏页在内存中停留更长时间
3. 保持dirty_background_ratio在合理范围内
# 增加dirty_ratio值到20(意味着脏页达到内存20%时才会强制同步写入)
echo 20 > /proc/sys/vm/dirty_ratio
# 增加dirty_expire_centisecs值到3000(30秒),让脏页在内存中停留更长时间
echo 3000 > /proc/sys/vm/dirty_expire_centisecs
# 保持dirty_background_ratio值不变(30是一个合理的值)
# 如果需要进一步增加脏页,可以考虑适当提高这个值,但不建议超过50
# echo 40 > /proc/sys/vm/dirty_background_ratio
参考:
[1] /proc/sys/vm/dirty_ratio 参数详解与最佳实践
[2] 脏页(Dirty Page)详解
详解&spm=1001.2101.3001.5002&articleId=154016019&d=1&t=3&u=ca40debfae4041aeb3957598124a5a45)
1613

被折叠的 条评论
为什么被折叠?



