mmap文件调用fallocate打洞后内存未减少?技术咨询
问题分析与解答
你的疑惑核心在于**MAP_PRIVATE映射的特性**和fallocate打洞操作的作用范围,咱们一步步拆解:
为什么调用fallocate后内存占用没变化?
你用了MAP_PRIVATE创建私有映射,这种映射的核心特点是:当进程第一次修改映射页时,内核会触发**写时复制(Copy-on-Write)**机制——把文件对应的物理页复制一份,变成当前进程的私有匿名页。从这一刻起,这份私有页就和原文件彻底脱离了关联:后续对文件的任何修改(包括fallocate打洞)都不会影响已经复制到进程内存里的私有页。
所以你调用fallocate只是在文件中创建了空洞,归还了文件系统的存储空间,但进程里之前通过写时复制得到的16M私有内存页,依然属于当前进程,不会被内核回收,自然在free -m和/proc/meminfo里看不到内存占用变化。
这段内存的去向?其他进程能拿到吗?
- 内存去向:只要你的进程还持有这段
MAP_PRIVATE的映射,这些私有页就会一直属于该进程,直到你调用munmap()主动释放这段映射,或者进程退出,内核才会把这些内存回收重新分配。 - 其他进程能否获取:不能。
MAP_PRIVATE的页是进程的私有资源,内核会严格隔离进程间的内存空间,其他进程无法直接访问这些内存,除非你的进程主动通过共享内存等机制把内存共享出去。
如何让打洞操作同时释放进程的内存?
如果想让fallocate打洞后,进程的对应内存也被回收,你需要把映射类型改成MAP_SHARED(共享映射):
- 共享映射的页直接和文件关联,不存在写时复制的私有副本。当你用
fallocate打洞后,内核会标记对应的映射页为无效,若进程不再访问这些页,内核就可以把它们的物理内存回收;如果后续访问,会触发缺页异常,内核会从文件的空洞区域读取全0的数据(此时文件里是空洞,不会占用文件系统空间)。
修改后的核心代码片段:
// 补全未定义的常量,同时将MAP_PRIVATE改为MAP_SHARED #define MMAP_SIZE (64 << 20) #define offset 0 // ... addr = (uint8_t *)mmap(NULL, MMAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
另外注意你的原始代码里有两处未定义的变量:MMAP_SIZE和offset,实际使用时需要补全合理的定义值。
内容的提问来源于stack exchange,提问作者Zihan




