[anon]的Size大而Private_Dirty小是正常现象,因Size仅表示虚拟地址空间大小,而Private_Dirty才反映实际占用的物理内存;这是延迟分配机制所致,如malloc/mmap仅预留虚拟地址,写入时才分配物理页。
![pmap -x 显示 [anon] 占用巨大但 smaps 里 private_dirty 很少](https://img.php.cn/upload/article/001/242/473/176880701688063.jpeg)
这是 Linux 内存管理中一个常见但容易误解的现象:pmap -x 显示 [anon] 区域的 Size(虚拟地址空间大小)非常大,而对应进程的 /proc/PID/smaps 中该区域的 Private_Dirty 却很小(甚至为 0)。这并不表示内存泄漏或异常,而是反映了虚拟内存与物理内存的本质区别。
为什么 [anon] 的 Size 巨大但 Private_Dirty 很小?
[anon] 是内核对匿名映射(如 malloc、mmap(MAP_ANONYMOUS))分配的虚拟内存区域的统称。它的 Size 字段(pmap -x 第二列)代表的是该段虚拟地址空间的长度 —— 它只是“划了块地”,不等于实际用了多少物理内存。
真正反映物理内存占用的是 smaps 中的:
- Private_Dirty:进程独占、已修改、尚未写回磁盘(即必须保留在 RAM 中)的私有页;
-
RSS(在
smaps中为Rss):当前驻留在物理内存中的总页数(含共享页、干净页、脏页); - MMU Page Tables 开销:大块虚拟地址空间本身会消耗少量内核内存(页表项),但这和用户态内存使用无关。
所以,Size 大 + Private_Dirty 小 = 进程申请了大量虚拟地址空间,但尚未真正写入(触发缺页中断),或只写了其中极小一部分。
典型场景:延迟分配(Lazy Allocation)和内存预分配
Linux 默认启用 overcommit 和 lazy allocation:调用 malloc 或 mmap 时,内核只建立页表项、不分配物理页;直到第一次写入某页,才触发缺页中断,真正分配一个物理页并清零(即所谓的 “zero page” 优化)。
常见例子包括:
- JVM 堆初始只 reserve 虚拟空间(如
-Xmx4g),实际使用随对象分配增长; - glibc malloc(ptmalloc)为避免频繁系统调用,会预先
mmap大块[anon]区域作为 arena,但大部分长期空闲; - 某些数据库或中间件显式
mmap(MAP_ANONYMOUS|MAP_NORESERVE)预留地址空间,按需 touch。
如何确认是否真有内存压力?
别只看 pmap -x 的 Size,应结合以下指标交叉判断:
- 查
/proc/PID/status中的 VmRSS(≈ RSS 总和)和 VmData(数据段+堆的 RSS); - 用
cat /proc/PID/smaps | awk '/^Size:/ {s+=$2} /^Rss:/ {r+=$2} /^Private_Dirty:/ {d+=$2} END {print "Size:",s,"KB; Rss:",r,"KB; Dirty:",d,"KB"}'汇总关键值; - 观察
free -h和cat /proc/meminfo中 MemAvailable 是否持续偏低; - 用
perf record -e 'mem-loads,mem-stores' -p PID或smaps_rollup工具分析实际访问模式。
需要关注什么?什么时候算异常?
只要 Private_Dirty 和 RSS 稳定、未持续增长,且系统无 OOM 或显著 swap,Size 大就是正常行为。
真正需警惕的情况是:
-
Private_Dirty持续线性增长,且不释放(如内存泄漏); -
smaps中出现大量MMUPageSize: 2MB或THP相关字段,但应用未主动启用透明大页,可能暗示 THP 合并异常导致碎片或浪费; -
pmap -x显示数百个零碎[anon]区域(每块几 MB),可能是 malloc 频繁分配/释放导致的虚拟地址碎片,影响 TLB 效率(可用cat /proc/PID/maps | grep anon | wc -l快速统计)。










