You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何malloc申请内存后物理内存占用未达预期?

问题解答:Linux下malloc内存读操作不占物理内存的原因

你的观察完全正确:堆内存的读操作在这种场景下不会触发物理页分配,只有写操作会,这是Linux内存管理的惰性分配和**写时复制(COW)**机制共同作用的结果,和匿名内存页的处理直接相关。

1. malloc/calloc的本质:虚拟地址分配而非物理内存分配

当你调用malloc(或你的代码中实际执行的calloc,从汇编可见)时,内核并没有立即为进程分配对应的物理内存,只是给进程划定了一段虚拟地址空间。这种"先占地址,再按需分配物理内存"的策略就是惰性内存分配,目的是避免浪费物理内存——毕竟很多进程申请内存后并不会立即使用所有内存。

2. 匿名内存页与全局零页映射

堆属于匿名内存区域(没有关联磁盘文件的内存),对于这类未被写入的虚拟页,内核会将它们暂时映射到一个全局共享的零页(内容全为0的物理页)。此时所有未被修改的匿名虚拟页都共享这一个零页,你的进程在读取这些页时,直接读取零页的内容即可,不需要为每个虚拟页单独分配物理内存。

从你的pmap输出可以看到关键证据:

00007fa6d1b9a000 1024016      12      12 rw---   [ anon ]

这里1024016 KB是虚拟地址空间的大小(对应你申请的1000MB),但12 KB是实际驻留的物理内存(RSS),说明只有极少量页被分配了物理内存,其余都在共享零页。

3. 读操作不触发物理页分配的原因

因为读操作不会修改零页的内容,多个进程可以安全地共享这个零页,内核没有必要为你的进程单独分配物理页。即使你循环读取a[i],内核仍然让你访问共享的零页,因此物理内存占用不会增加。

4. 写操作触发物理页分配(写时复制)

当你执行a[i] = 1;时,你试图修改虚拟页的内容。此时内核检测到该虚拟页映射的是共享的零页,就会触发写时复制机制:

  1. 为当前虚拟页分配一个新的物理页
  2. 将零页的内容复制到新物理页中
  3. 更新进程的页表,让该虚拟页映射到新物理页
  4. 执行写入操作(将1写入新物理页)

当你循环写入所有a[i]时,每个虚拟页都会触发这个过程,最终所有1000MB对应的物理页都会被分配,因此free和pmap会显示物理内存占用达到1000MB。

补充:calloc的特殊情况

你的代码中写的是malloc,但汇编显示实际调用了calloc——这是因为编译器优化了内存初始化操作(malloc后如果没有初始化,编译器可能替换为calloc来保证内存为0)。不过这并不影响原理:calloc的"初始化零"也是通过映射零页实现的,不需要实际分配物理内存,和直接用malloc后读未初始化内存(在Linux下实际也是零)的行为一致。

内容的提问来源于stack exchange,提问作者Black Pan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 16:47:10