我有一个进程会做很多光刻计算,所以我使用 mmap 为内存池分配一些内存。当进程需要大块内存时,我使用mmap分配一块块,用完后放入内存池,如果进程再次需要相同的块内存,直接从池中获取,不使用内存再次映射。(不是分配所有需要的内存并在进程开始时将其放入池中)。在 mmaps 函数之间,还有一些内存 malloc 没有用到 mmap,比如 malloc() 或 new()。
现在的问题是:如果我在放入内存池之前使用 memset() 将所有块数据设置为零,则该进程将使用过多的虚拟内存,格式为“mmap(size)=virtual address”:
mmap(4198400)=0x2aaab4007000 mmap(4198400)=0x2aaab940c000 mmap(8392704)=0x2aaabd80f000 mmap(8392704)=0x2aaad6883000 mmap(67112960)=0x2aaad7084000 mmap(8392704)=0x2aaadb085000 mmap(2101248)=0x2aaadb886000 mmap(8392704)=0x2aaadba89000 mmap(67112960)=0x2aaadc28a000 mmap(2101248)=0x2aaae028b000 mmap(2101248)=0x2aaae0c8d000 mmap(2101248)=0x2aaae0e8e000 mmap(8392704)=0x2aaae108f000 mmap(8392704)=0x2aaae1890000 mmap(4198400)=0x2aaae2091000 mmap(4198400)=0x2aaae6494000 mmap(8392704)=0x2aaaea897000 mmap(8392704)=0x2aaaeb098000 mmap(2101248)=0x2aaaeb899000 mmap(8392704)=0x2aaaeba9a000 mmap(2101248)=0x2aaaeca9c000 mmap(8392704)=0x2aaaec29b000 mmap(8392704)=0x2aaaecc9d000 mmap(2101248)=0x2aaaed49e000 mmap(8392704)=0x2aaafd6a7000 mmap(2101248)=0x2aacc5f8c000
mmap 最后 - 第一个 = 0x2aacc5f8c000 - 0x2aaab4007000 = 8.28G
但是如果我在放入内存池之前不调用 memset:
mmap(4198400)=0x2aaab4007000 mmap(8392704)=0x2aaab940c000 mmap(8392704)=0x2aaad2480000 mmap(67112960)=0x2aaad2c81000 mmap(2101248)=0x2aaad6c82000 mmap(4198400)=0x2aaad6e83000 mmap(8392704)=0x2aaadb288000 mmap(8392704)=0x2aaadba89000 mmap(67112960)=0x2aaadc28a000 mmap(2101248)=0x2aaae0a8c000 mmap(2101248)=0x2aaae0c8d000 mmap(2101248)=0x2aaae0e8e000 mmap(8392704)=0x2aaae1890000 mmap(8392704)=0x2aaae108f000 mmap(4198400)=0x2aaae2091000 mmap(4198400)=0x2aaae6494000 mmap(8392704)=0x2aaaea897000 mmap(8392704)=0x2aaaeb098000 mmap(2101248)=0x2aaaeb899000 mmap(8392704)=0x2aaaeba9a000 mmap(2101248)=0x2aaaec29b000 mmap(8392704)=0x2aaaec49c000 mmap(8392704)=0x2aaaecc9d000 mmap(2101248)=0x2aaaed49e000
mmap 最后 - 第一个 = 0x2aaaed49e000 - 0x2aaab4007000= 916M
所以第一个进程将“内存不足”并被杀死。
在这个过程中,mmap内存块虽然被分配了,但不会被完全使用,甚至不会被使用,我的意思是,例如在校准之前,进程mmap 67112960(64M),它不会使用(在此写入或读取数据内存区域)或仅使用前 2M 字节,然后放入内存池。
我知道 mmap 只是返回虚拟地址,物理内存使用延迟分配,它会在读取或写入这些地址时分配。
但让我困惑的是,为什么虚拟地址增加了这么多?我使用的是 centos 5.3,内核版本是 2.6.18,我在 libhoard 和 GLIBC(ptmalloc) 上都尝试了这个过程,两者的行为相同。
有没有人遇到过同样的问题,可能的根本原因是什么?
谢谢。