C程序中malloc分配内存后,系统可用内存为何未明显下降?
为何内存分配程序未按预期消耗物理内存?
我想要编写一个每秒分配一段内存的C程序,模拟内存不足(OOM)场景(故意不释放内存),并输出剩余可用内存。以下是Linux平台的程序代码:
#include <stdio.h> #include <sys/types.h> #include <unistd.h> #include <stdlib.h> int main() { size_t mbs = 500 * 1000000; // 500mb while(true) { sleep(1); void* tmp = malloc(mbs); system("free"); } return 0; }
调用system执行free命令查看可用内存,我预期可用内存每秒减少500MB,但实际约32GB内存中可用内存始终维持在25GB左右,尝试10MB、100MB分配量结果一致。Windows平台类似程序也出现相同现象:
#include <stdio.h> #include <stdlib.h> #include <windows.h> int main() { size_t mbs = 500 * 1000000; // 500mb while(true) { Sleep(2); void* tmp = malloc(mbs); system("systeminfo |find \"Available Physical Memory\""); } return 0; }
为何未观察到内存消耗的下降?
核心原因:虚拟内存与写时复制机制
你的程序仅调用malloc(Windows底层对应HeapAlloc),但并未对分配的内存块执行实际写入操作。现代操作系统采用虚拟内存管理和**写时复制(Copy-On-Write, COW)**机制:
malloc只是向操作系统申请了虚拟地址空间,内核不会立即分配实际物理内存;- 只有当进程首次向该虚拟地址空间写入数据时,内核才会真正分配物理页帧并完成映射。
free(Linux)或systeminfo(Windows)显示的是已占用的物理内存,而非进程持有的虚拟内存空间,因此你无法观察到预期的内存消耗下降。
解决方法:触发物理内存分配
要让系统真正分配物理内存,需对malloc返回的指针指向的内存执行写入操作,例如用memset填充整个内存块:
Linux 修改后代码
#include <stdio.h> #include <sys/types.h> #include <unistd.h> #include <stdlib.h> #include <string.h> int main() { size_t mbs = 500 * 1000000; // 500mb while(1) { sleep(1); void* tmp = malloc(mbs); if (tmp == NULL) { perror("malloc failed"); break; } // 写入内存触发物理页分配 memset(tmp, 0, mbs); system("free"); } return 0; }
Windows 修改后代码
#include <stdio.h> #include <stdlib.h> #include <windows.h> #include <string.h> int main() { size_t mbs = 500 * 1000000; // 500mb while(1) { Sleep(2); void* tmp = malloc(mbs); if (tmp == NULL) { printf("malloc failed\n"); break; } // 写入内存触发物理页分配 memset(tmp, 0, mbs); system("systeminfo |find \"Available Physical Memory\""); } return 0; }
额外说明
- 务必添加内存分配失败判断:当物理内存耗尽时,
malloc会返回NULL,此时终止循环避免无效申请; - Linux下可通过
top或ps aux查看进程的虚拟内存(VSZ)和物理内存(RSS),RSS会随写入操作增长;Windows下可在任务管理器查看进程的「工作集(Working Set)」。
内容的提问来源于stack exchange,提问作者TheMemeMachine
相关产品推荐
相关产品推荐

