为什么memset函数会使虚拟内存如此之大

时间:2013-09-01 05:52:45

标签: memory-management linux-kernel virtual-memory memset

我有一个进程会做很多光刻计算,所以我使用mmap为内存池分配一些内存。当进程需要大块内存时,我使用mmap来分配一个chunk,在使用之后将它放入内存池,如果在进程中再次需要相同的chunk内存,则直接从池中获取,不使用内存再次映射。(不分配所有需要的内存并在进程开始时将其放入池中)。在mmaps函数之间,有一些内存malloc没有使用mmap,比如malloc()或new()。

现在的问题是: 如果我在将所有块数据放入内存池之前使用memset()将所有块数据设置为ZERO,则该过程将使用过多的虚拟内存,格式为“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 last - first = 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 last - first = 0x2aaaed49e000 - 0x2aaab4007000 = 916M

所以第一个过程将“内存不足”并被杀死。

在这个过程中,mmap内存块将不会被完全使用或者甚至不被使用,尽管它被分配,我的意思是,例如,在校准之前,过程mmap 67112960(64M),它将不会被使用(写入或读取)此内存区域中的数据)或只使用前2M字节,然后放入内存池。

我知道mmap只返回虚拟地址,物理内存使用延迟alloc,它会在读取或写入这些地址时分配。

但令我困惑的是,为什么虚拟地址增加如此之多?我使用了centos 5.3,内核版本是2.6.18,我在libhoard和GLIBC(ptmalloc)上尝试了这个过程,两者都有相同的行为。

之前是否有人遇到同样的问题,可能的根本原因是什么?

感谢。

1 个答案:

答案 0 :(得分:1)

VMA(虚拟内存区域,AKA内存映射)不需要是连续的。您的第一个示例使用~256 Mb,第二个示例使用~246 Mb。

常见的malloc()实现会自动使用mmap()进行大型分配(通常大于64Kb),并使用munmap()释放相应的块。因此,您无需mmap()手动进行大量分配,您的malloc()库将会处理此问题。

mmap()时,内核返回特殊零页面的COW副本,因此在写入之前它不会分配内存。您的归零会导致内存真正被分配,最好将其返回到分配器,并在需要时请求新的内存块。

结论:不要编写自己的内存管理,除非系统已经证明不足以满足您的需求,然后只有在您已经证明它明显更好地满足您的实际负载需求时才使用您自己的内存管理。