内存映射文件对大缓冲区有什么优势吗?

5
我的程序处理需要存储在连续内存中的大型数据集(几个千兆字节)。使用std::allocator(即mallocnew)分配内存会导致系统停顿,因为大量的虚拟内存被保留,物理内存被填满。
由于该程序通常只会一次处理一小部分,所以我的问题是,是否使用内存映射文件会提供优势(即mmap或Windows等效方法)。即创建一个大型稀疏临时文件并将其映射到虚拟内存。或者是否有另一种技术可以改变系统的分页策略,使每次加载到物理内存中的页面更少。
我试图避免构建流机制,每次仅加载文件的一部分,并依靠系统的vm分页。

你会经常在不同的部分之间跳转吗? - Marc B
1
这取决于算法(有许多不同的算法)。基本上,它们可以分为以下几类:
  • 从开头到结尾的顺序读取
  • 在不同的大段中进行并行顺序读取
  • 在大段内进行随机访问(例如在递归深度优先下降期间)
  • 其他随机访问
- tmlen
3个回答

5

是的,mmap 有加速的潜力

需要考虑以下几点:

  • 记住虚拟内存管理器会按页大小(Linux 上为 4k)分页读写。
  • 如果你的内存访问时间上的局部性很好,这个方法会有效。但是,如果你在整个文件上进行随机访问,你最终会遇到大量寻址和抖动问题。因此,请考虑你的“小部分”是否对应于文件的局部位。
  • 对于大块内存分配,mallocfree 会使用带有 MAP_ANONmmap。因此,内存映射文件的区别仅在于你要让虚拟内存管理器来处理 I/O。
  • 考虑使用 madvise 来帮助虚拟内存管理器更好地进行分页。
  • 当你使用 openread(还有像 erenon 建议的 posix_fadvise)时,你的文件仍然被缓存在内存中(即它不会立即被写出),除非你也使用了 O_DIRECT。因此,在这两种情况下,你都依赖于内核进行 I/O 调度。

3
如果数据已经在文件中,特别是在非顺序情况下,这将加快速度。(在顺序情况下,read 更胜一筹)
如果使用 openread,考虑同时使用 posix_fadvise

2
这实际上取决于您的实现。将文件映射到内存中有几个优点,内核可以利用这些优点:
  • 内核知道mmap()页面的内容已经存在于磁盘上。如果它决定驱逐这些页面,它可以省略写回。

  • 您可以减少复制操作:read()操作通常先将数据读入内核内存,然后将其复制到用户空间。

  • 减少的复制也意味着使用更少的内存来存储文件中的数据,这意味着可以为其他用途提供更多的内存,这也可以减少分页。

    这也是为什么在I/O库中使用大缓存通常不是一个好主意的原因:现代内核已经缓存了从磁盘读取的所有数据,将副本缓存在用户空间意味着可缓存的数据量实际上会减少。

当然,您还可以避免在应用程序中缓冲未知大小的数据所带来的许多麻烦。但这只是对程序员的一种方便。
然而,即使内核可以利用这些属性,它也不一定这样做。我的经验是LINUX的mmap()通常很好;但在AIX上,我曾经见过非常糟糕的mmap()性能。因此,如果您的目标是性能,那就是老方法-比较、决定。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接