应查看RSS(Resident Set Size)而非malloc返回值,因RSS反映进程实际占用的物理内存;ps、pmap、/proc/pid/statm均可获取RSS,其中pmap -x第三列RSS加总即为总物理内存占用。

直接看进程实际用了多少物理内存,别信 malloc 返回的地址大小;调试 malloc 本身要绕过 glibc 默认行为,否则看到的全是优化后的黑盒。
怎么看一个进程真实占用的物理内存(RSS)
malloc 分配的是虚拟地址,不等于物理内存占用。真正反映压力的是 RSS(Resident Set Size),即当前驻留在物理内存中的页数。
-
ps -o pid,comm,rss,%mem -p <pid></pid>:快速查单个进程的 RSS 和内存占比 -
pmap -x <pid></pid>:列出所有内存映射段,第三列RSS是关键,加总就是该进程实际占的物理内存 -
cat /proc/<pid>/statm</pid>:输出 7 个数字,第二个是 RSS 页数(需 ×4096 换算为字节) - 注意:
top中的RES列和ps的RSS是同一指标,但VIRT包含未分配/未触碰的 mmap 区域,不能反映真实压力
为什么 malloc(20) 却看到 brk 增加了 132KB
第一次调用 malloc 时,glibc 会通过 brk 向内核申请一大块内存(如 135168 字节),并非按需分配。这是为了减少系统调用开销。
- 底层原因:glibc 的
ptmalloc使用sbrk预分配一个“主分配区”(main arena),最小单位受MMAP_THRESHOLD和对齐规则影响 - 132KB 不是 magic number:它由头部开销(32 字节)、对齐到 page 边界(4096 字节)及默认
TOP_PAD共同决定 - 后续小 malloc(如再申请 20 字节)通常从这块预分配内存中切分,不再触发
brk - 验证方式:用
strace -e brk,mmap ./your_program可捕获首次brk调用的实际增量
如何让 malloc 行为“可观察”,避免优化干扰
默认 glibc 会对小内存使用 fastbins、tcache 等优化机制,导致多次 malloc/free 看不到内存归还——这不是 bug,是设计使然。要调试真实分配/释放行为,必须关闭缓存。
- 设置环境变量:
MALLOC_TRIM_THRESHOLD_=0 MALLOC_TOP_PAD_=0 MALLOC_MMAP_THRESHOLD_=0,强制禁用 tcache 和 mmap 回退 - 配合
malloc_trim(0)主动收缩堆顶,观察brk是否回落(返回 1 表示成功) - 启用调试检查:
MALLOC_CHECK_=2,会在检测到 double-free、越界写时中止并打印错误,但会显著拖慢运行速度 - 注意:
MALLOC_CHECK_在生产环境禁用,仅用于开发期定位问题
调试 malloc 源码本身需要替换 libc
想单步进 malloc 函数内部?系统自带的 libc.so 是编译优化过的,没有调试符号。必须自己编译带 --enable-debug 的 glibc。
- 先确认版本:
ldd --version或getconf GNU_LIBC_VERSION - 下载对应源码(如
glibc-2.39),configure --prefix=/usr --enable-debug=yes,再make - 运行时用
LD_PRELOAD=/path/to/build/libc.so ./your_program加载自定义 libc - 用
gdb --args ./your_program启动后,break malloc就能停在源码行;但注意:某些系统调用(如brk)仍需catch syscall brk捕获 - 坑点:自定义 libc 与系统动态链接器(
ld-linux-x86-64.so.2)版本不匹配会导致Segmentation fault,务必用同源 build 出的ld
真正难的不是看到 malloc 分配了多少,而是理解它为什么这样分——比如 tcache 如何掩盖内存泄漏、brk 和 mmap 的切换阈值在哪、malloc_trim 为何有时返回 0。这些细节藏在 malloc.c 的注释和 malloc_stats() 输出里,而不是 man 手册中。


















