Linux进程RSS异常表现为持续增长或与其他内存指标严重不匹配,需通过/proc/pid/statm、status、pmap及smaps等多维度精准定位,区分匿名页、文件映射与共享内存,并结合PSS排除共享页虚高干扰。

Linux 进程 RSS 异常,通常表现为某个进程的 RSS(Resident Set Size)持续增长、远超预期,或与其他内存指标(如 VSZ、PSS)严重不匹配。这往往暗示内存泄漏、缓存未释放、大对象驻留、mmap 映射异常,或 JVM/Python 等运行时环境的堆外内存问题。定位需结合多维度观察,不能只看 top 或 ps 的 RSS 值。
查 RSS 真实值:别只信 top
top 默认显示的 RSS 是近似值,且单位易混淆(如显示为 KiB 但标成 “%MEM”)。应优先使用更精确的接口:
-
读取
/proc/<pid>/statm</pid>:第2列是 RSS 页数(单位为 PAGE_SIZE,通常是 4KB),awk '{print $2*4}' /proc/1234/statm得到 KB 数 -
解析
/proc/<pid>/status</pid>:关注rss:行(单位 KB),比 statm 更直观;同时留意rss_anon:(匿名页)、rss_file:(文件映射页)、rss_shmem:(共享内存页),可初步判断内存类型分布 -
用 pmap -x
:列出所有内存段的 RSS 占用,重点看大块 anon、heap、stack、[anon:.heap] 或 [anon:Glide] 类映射——这些往往是泄漏源头
看内存增长趋势:动态比静态更重要
单次快照无法确认是否异常,需观测变化规律:
- 用
watch -n 1 'cat /proc/1234/status | grep -E "^(VmRSS|rss:)"'每秒刷新,观察 rss 是否线性/阶梯式上涨 - 配合
/proc/<pid>/smaps_rollup</pid>(内核 4.14+)查看汇总的 anon/rss/file/shmem 分布,若anon:持续涨而file:稳定,大概率是堆或 mmap 匿名页泄漏 - 对 Java 进程,加
-XX:+PrintGCDetails -XX:+PrintGCTimeStamps并观察 GC 后老年代是否不回落——RSS 高但堆内存不高,说明是堆外内存(如 DirectByteBuffer、Netty PooledByteBuf)在吃内存
定位泄漏模块:从 mmap 到用户代码
RSS 异常常源于 mmap 分配未释放,或运行时缓存失控:
- 用
pmap -x <pid> | sort -k3 -nr | head -10</pid>找 RSS 最大的 10 个内存段,看是否有异常大块(如 >100MB)且标注为[anon:.bss]或[anon:thread stack] - 用
cat /proc/<pid>/maps | awk '$6 ~ /\[anon\]/ {print $0}' | wc -l</pid>统计匿名映射数量,过多(如数千)可能表明线程/连接池失控或 mmap 泄漏 - C/C++ 程序可用
LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so jemalloc 可视化工具或valgrind --tool=massif(注意性能开销)抓内存分配热点;Go 程序用pprof的goroutine和heapprofile;Python 用tracemalloc或psutil.Process().memory_info().rss+gc.get_objects()
排除干扰项:RSS 不等于“该进程独占”
理解 RSS 的共享本质,避免误判:
- RSS 包含共享库代码页、共享内存(shmem)、tmpfs 文件等——多个进程共用同一物理页,但各自 RSS 都计入,造成“虚高”
- 对比
PSS(Proportional Set Size):它把共享页按进程数均摊,/proc/<pid>/smaps</pid>中每段有 PSS 行,总和更反映真实内存贡献;awk '/^Pss:/ {s+=$2} END {print s}' /proc/1234/smaps - 检查是否被 cgroup 限内存:若
/sys/fs/cgroup/memory/.../memory.limit_in_bytes设置过小,RSS 可能因 OOM Killer 干预或内核回收策略表现异常











