脏页(Dirty Page)详解

一、什么是脏页(Dirty Page)

定义:

脏页是指 内存中被修改过但还没写回磁盘的页(page)

当写入文件(如 write() 系统调用)时,数据通常不会立刻写入磁盘,而是:

  1. 内核先把数据写入 页缓存(Page Cache)
  2. 这块缓存页被标记为 “脏”(dirty)
  3. 后台的 写回(writeback)线程 在合适的时机(比如页太多、时间到、内存压力大)将脏页写入磁盘;
  4. 写入完成后,页标记为 干净(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
  1. dirty_ratio
  • 含义:系统中可用内存的百分比,当脏页占比超过该值时,进程自身的写操作会被阻塞,直到脏页写回部分。
  • 默认值:20

示例

内存 8GB → 超过 1.6GB 脏页时,用户写操作被阻塞。

  1. dirty_background_ratio
  • 含义:系统中可用内存的百分比,当脏页占比超过这个值时,内核后台线程(flush)开始异步写回。
  • 默认值:10

示例

内存总量 = 8GB
dirty_background_ratio = 10
→ 当脏页超过 0.8GB 时,后台线程开始写回。
  1. dirty_expire_centisecs
  • 含义:脏页在内存中存在超过此时间后(单位为百分之一秒),即使未达到比例,也会被写回。
  • 默认值:3000(即 30 秒)
  • 影响:控制数据写回延迟,值越大缓存越久,但断电丢数据风险更高。
  1. dirty_writeback_centisecs
  • 含义:后台线程写回任务的执行周期。
  • 默认值:500(即 5 秒)
  • 意思:每隔 5 秒,内核会扫描脏页并尝试写回。
  1. dirty_bytesdirty_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)详解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值