脏页堆积但iostat无磁盘热点,主因是swap、tmpfs或共享匿名映射产生的脏页不经过块设备I/O路径;需查pswpout、/proc/swaps、tmpfs使用量及mmap(MAP_ANONYMOUS|MAP_SHARED)进程。

脏页堆积但 iostat 无明显磁盘热点,先确认脏页来源类型
Linux 的 dirty_pages 不一定都来自文件系统写回——匿名页(如进程堆、mmap 私有匿名区)的换出(swap)也会产生脏页,但这类页不走 pdflush 或 writeback 路径,不会触发块设备写请求,因此 iostat 看不到对应磁盘 activity。此时 /proc/meminfo 中的 Dirty: 和 Writeback: 可能偏高,但 pgpgout(每秒换出页数)和 pswpin/pswpout(swap in/out 次数)才是关键线索。
- 运行
grep -E "Dirty|Writeback|pgpgout|pswpin|pswpout" /proc/vmstat,若pswpout显著上升而pgpgout增长平缓,基本可断定是 swap 引起的脏页堆积 - 检查
/proc/swaps是否启用 swapfile 或 swap partition;用swapon --show=NAME,TYPE,SIZE,USED,PRI确认活跃 swap 设备 - 注意:即使
swapon -s显示 swap 已关闭,内核仍可能因vm.swappiness=100或内存压力在tmpfs(如/dev/shm)上触发匿名页回收,这部分页会标记为 dirty 但不落地到磁盘
排查 tmpfs 和 shm 匿名页污染
tmpfs 是基于内存的文件系统,其内容本质是匿名页,且默认可被 swap。当应用往 /dev/shm 或自挂载的 tmpfs 写入大量数据(如数据库 shared memory segment、大 buffer mmap),这些页一旦变 dirty,就计入 Dirty: 统计,但不会触发块设备 I/O——因为没磁盘后端。
- 用
df -t tmpfs查看所有 tmpfs 挂载点使用量,重点关注/dev/shm、/run、/sys/fs/cgroup下的子挂载 - 对可疑挂载点执行
find /dev/shm -type f -ls | sort -k7nr | head -10,找大文件或已删除但未释放的“幽灵文件”(lsof +L1可辅助定位) - 临时禁用 tmpfs swap 行为:挂载时加
noexec,nosuid,nodev,mode=1777,size=2G,mpol=bind:0并设vm.mmap_min_addr=65536减少 mmap 分配风险;长期方案需控制应用内存使用模式
确认是否 mmap(MAP_ANONYMOUS|MAP_SHARED) 导致脏页无法回收
共享匿名映射(mmap(..., MAP_ANONYMOUS|MAP_SHARED))产生的页,在 fork 后被子进程修改时会触发写时复制(COW),但若父/子均未调用 msync(MS_SYNC) 或 munmap,这些页会持续处于 dirty 状态,且不归属任何文件,无法通过 sync 或 echo 3 > /proc/sys/vm/drop_caches 清理。
- 用
cat /proc/[pid]/maps | grep -E "anon|shared" | awk '{print $5,$6}' | sort | uniq -c | sort -nr扫描各进程的匿名共享映射大小 - 结合
pstack [pid]和lsof -p [pid] | grep mem判断是否为数据库(PostgreSQL shared memory)、JVM(-XX:+UseSHM)、或自定义 IPC 使用了该模式 - 这类页的生命周期由进程控制:只有进程退出、显式
munmap或触发 OOM killer 才会真正释放;echo 1 > /proc/sys/vm/compact_memory对它们无效
为什么 iostat 看不出问题?关键在 writeback vs swap vs tmpfs 路径分离
iostat 统计的是 blk_mq_make_request 层面的块设备 I/O,只覆盖文件系统 writeback 和 swap device I/O。而 tmpfs 页面回收走的是 shrink_slab → shrink_page_list → try_to_unmap 路径;匿名页 swap out 走的是 swap_writepage → submit_bio,但如果 swap 是 file-backed(swapfile),且该文件本身在 ext4/xfs 上,I/O 会被归入对应 block device;但若 swap 是 LVM LV 或 zram,iostat -x 需指定对应设备名(如 zram0)才可见。
- 运行
iostat -x 1 3时务必加上-d参数并列出所有块设备:lsblk -d -o NAME,TYPE,SIZE,ROTA,MODEL,避免漏看 zram、loop、nvme ns -
cat /proc/buddyinfo和cat /proc/pagetypeinfo可辅助判断是否因内存碎片导致 direct reclaim 频繁,进而推高 dirty page 回收延迟 - 最易忽略的一点:某些容器运行时(如 containerd + overlayfs)在
/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs下创建的 tmpfs mount,其 dirty 页完全不可见于宿主机 iostat,必须进容器命名空间查









