1

我有一个进程会做很多光刻计算,所以我使用 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) 上都尝试了这个过程,两者的行为相同。

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

谢谢。

4

1 回答 1

1

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

常见的malloc()实现mmap()自动用于大型分配(通常大于 64Kb),使用munmap(). 因此,您无需mmap()手动进行大量分配,您的malloc()库会处理好这一点。

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

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

于 2013-09-01T12:47:53.890 回答