C++ mmap与使用新内存分配的内存

C++ mmap与使用新内存分配的内存,c++,performance,memory-management,C++,Performance,Memory Management,我有一个BitVector类,它可以使用new动态分配内存,也可以mmap文件。在小文件中使用mmap时,性能没有明显差异,但在使用16GB文件时,我发现mmap文件的速度远远低于使用new分配的内存。(大约慢10倍或更多)注意,我的机器有64GB的RAM 所讨论的代码是从一个大的磁盘文件加载值,并将它们放入一个Bloom过滤器,该过滤器使用myBitVector类进行存储 起初我认为这可能是因为mmap文件的备份与我从中加载的文件位于同一磁盘上,但这似乎不是问题所在。我将这两个文件放在两个物理

我有一个
BitVector
类,它可以使用
new
动态分配内存,也可以
mmap
文件。在小文件中使用mmap时,性能没有明显差异,但在使用16GB文件时,我发现mmap文件的速度远远低于使用
new
分配的内存。(大约慢10倍或更多)注意,我的机器有64GB的RAM

所讨论的代码是从一个大的磁盘文件加载值,并将它们放入一个Bloom过滤器,该过滤器使用my
BitVector
类进行存储

起初我认为这可能是因为mmap文件的备份与我从中加载的文件位于同一磁盘上,但这似乎不是问题所在。我将这两个文件放在两个物理上不同的磁盘上,性能没有变化。(尽管我相信他们在同一个控制器上。)

然后,我使用
mlock
尝试将所有内容强制放入RAM,但mmap实现仍然非常缓慢

所以,目前我只是直接分配内存。为了进行比较,我在代码中唯一要更改的是
位向量
构造函数的标志

请注意,为了衡量性能,我会查看
top
,并查看每秒可以添加多少状态到Bloom过滤器中。当使用
mmap
时,CPU使用率甚至没有在
top
上注册-尽管
jbd2/sda1-8
开始上升(我在Ubuntu服务器上运行),这看起来是一个处理驱动器日志的进程。输入和输出文件存储在两个硬盘上

有人能解释性能上的巨大差异吗

谢谢

首先,
mmap
是用于访问系统虚拟内存的系统调用或接口。
现在,在linux中(我希望您使用的是*nix),通过延迟加载或更常见的写时复制,可以实现很多性能改进。

对于mmap,也实现了这种延迟加载。

发生的情况是,当您在文件上调用mmap时,内核不会立即为要映射的文件分配主内存页。
相反,它会等待程序从幻觉页进行写入/读取,在此阶段,会发生页面错误,然后,相应的中断处理程序将实际加载可保存在该页面帧中的特定文件部分(页面表也将更新,以便下次读/写同一页面时,它将指向有效的帧)。

现在,您可以使用
mlock
madvise
MAP\u用mmap填充
标志等来控制此行为。
MAP\u使用mmap填充
标志,告诉内核在调用返回之前将文件映射到内存页,而不是每次访问新页时都出现页面错误。因此,在加载文件之前,函数将被阻止。

从手册页: MAP_POPULATE (since Linux 2.5.46) Populate (prefault) page tables for a mapping. For a file mapping, this causes read-ahead on the file. Later accesses to the mapping will not be blocked by page faults. MAP_POPULATE is supported for private mappings only since Linux 2.6.23. MAP_填充(自Linux 2.5.46起) 为映射填充(预故障)页表。存档 映射时,这会导致对文件进行预读。后期访问 到映射将不会被页面错误阻止。 MAP_POPULATE仅支持私有映射,因为 Linux 2.6.23。

AFAIK,mmap读取大页面的默认策略不是很好。在设置MAP_POPULATE标志并使用madvise以及标记MADV_SEQUENTIAL(如果您的访问是SEQUENTIAL)或MADV_RANDOM(如果是RANDOM access)或MADV_WILLNEED(防止重新加载页面)后,您是否可以重新运行案例。这肯定是一种意外行为,特别是因为
operator new
使用
malloc
,它使用
mmap
处理大型请求!当你说“使用16GB文件”时,这表明你使用的是真实的文件,而不是
/dev/shm
中的文件?如果是这样的话,特别是因为你注意到日志记录过程在上升,那么速度的减慢可能是由于readahead的磁盘访问和故障(尽管我不知道操作系统在磁盘上应该为空零页做什么)。@Damon-我使用的是一个真实的文件,而不是临时文件。我是随机访问它的,虽然如果它被锁定在内存中,这似乎并不重要。@ArunMu-好建议。机器现在很忙,但我会在早上试用。请注意,
/dev/shm
实际上不是一个临时文件,但这是一种要求操作系统“给我虚拟内存”的方式,因此,如果分配内存是您想要的(而不是读取真正的文件),则更接近您想要的。页面错误应复制零页面,且无需锁定。