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

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

以前有人遇到同样的问题,可能的根源是什么?

谢谢。


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

常见的malloc()实现自动使用mmap()进行大分配(通常大于64Kb),并使用munmap()释放相应的块。 所以你不需要为大分配手动mmap() ,你的malloc()库会照顾到这一点。

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

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

链接地址: http://www.djcxy.com/p/82717.html

上一篇: Why memset function make the virtual memory so large

下一篇: how memory allocation works at extremes?