人人都会AI编程

smem、pmap:进程内存占用分析

更新时间:2026-07-12

当系统内存紧张,或者应用出现疑似内存泄漏时,仅靠 topfree 提供的粗略数字往往不够。smempmap 是两个轻量级工具,能帮你更精细地解剖进程的实际内存占用。


smem — 看清“按比例分摊”后的真实内存

传统工具(如 ps)报告的 RSS(常驻内存集)会把共享库(如 libc)的内存重复计入每一个使用它的进程,导致多个进程的内存加起来远大于物理内存,容易引起误判。smem 默认显示 PSS(按比例分摊集),它将共享内存页按使用进程数均分,让你看到每个进程真正“摊派”到它身上的内存量。

常见用法:

# 查看所有进程,按 PSS 降序排列
smem -r -s pss

# 查看特定用户(如 www-data)的内存占用汇总
smem -u www-data

# 按进程分组,显示总 PSS 和共享内存
smem -p

# 生成饼图(需要 python-matplotlib)
smem --pie name

实用场景:

  • 快速定位“内存大户”,尤其是大量子进程共享同一库的场景(如 Apache prefork 模式),RSS 可能会产生误导,而 PSS 更接近真实开销。
  • 评估容器或 cgroup 内整体内存占用,smem 支持按用户、进程名甚至映射文件来汇总。

示例输出解读:

  PID User     Command                         Swap      USS      PSS      RSS
 1234 root     /usr/bin/java                      0   512.0M   523.5M   580.2M
 5678 mysql    /usr/sbin/mysqld                   0   256.3M   270.1M   340.8M
  • USS:进程独自占用的非共享内存(唯一集合)。杀掉进程可释放的全部内存。
  • PSS:独自占用 + 均摊的共享部分,最常用于跨进程汇总比较。
  • RSS:常驻内存,包含完全共享部分,数值会偏大不适用于跨进程求和。

pmap — 查看单个进程的内存地图

pmap 能展开进程的虚拟内存布局,列出其中每一个映射区域的具体大小、权限和映射文件。对于定位内存泄漏、大块匿名内存或文件映射异常十分有效。

基本用法:

# 显示进程 1234 的内存映射详情
pmap -x 1234

# 只显示设备号和映射文件,便于追踪打开的文件
pmap -d 1234

# 显示扩展格式(包含脏页等)
pmap -X 1234

pmap -x 输出各列含义:

  • Address:虚拟内存起始地址
  • Kbytes:区域大小(KB)
  • RSS:常驻物理内存(KB)
  • Dirty:脏页大小(需要写回或释放时写回的页)
  • Mode:权限(r=读, w=写, x=执行, s=共享, p=私有)
  • Mapping:映射的文件路径,或 [ anon ] 表示未关联文件的匿名内存(如堆、栈、mmap 分配的内存)

实用场景:

  • 进程 RSS 很大,但不知道是哪些部分造成的。通过 pmap -x PID 可以快速看到是某个大文件被映射进内存,还是存在大量匿名内存(可能是应用内存泄漏)。
  • 分析 JVM 或数据库进程的内存结构:你会发现堆外内存往往以匿名区域的形式出现,通过 pmap 能直观感知其规模。
  • 快速判断共享库加载情况,查看 [ anon ] 内存是否异常膨胀。

典型排错流程:

  1. 取得目标进程 PID。
  2. 运行 pmap -x PID | sort -k3 -n -r | head -20,按 RSS 降序列出占用最大的前 20 块内存区域。
  3. 观察 Mapping 列:
  • 大量小块的 [ anon ]:可能是 malloc 碎片或内存泄漏;
  • 单个超大 [ anon ]:可能是堆或定制 mmap;
  • 大文件映射:检查该文件是否应持续驻留内存。
  1. 结合 strace/proc/PID/smaps 等进一步求证。

总结对比

| 工具 | 擅长维度 | 典型命令 |
|------|---------|---------|
| smem | 多进程横向比较、按PSS看清共享分摊后的真实占用 | smem -r -s pss |
| pmap | 单进程纵向解剖、展现每个内存区域的细节 | pmap -x PID |

两个工具可以相互配合:先用 smem 找出异常消耗内存的进程,再用 pmap 深入分析该进程内部的内存分布,往往能迅速逼近问题根源。