【问题标题】:Memory mapped files performance - memory management when working with large data sets内存映射文件性能 - 处理大型数据集时的内存管理
【发布时间】:2011-05-02 11:03:33
【问题描述】:

我有一种情况,我需要处理大量 (15-30) 个大型(数百 mb)数据结构。它们不会同时进入记忆。更糟糕的是,在它们上运行的算法适用于所有这些结构,即不是第一个,而是另一个等等。我需要尽可能快地做到这一点。

所以我想我会在磁盘上分配内存,在将数据加载到内存时基本上是数据的直接二进制表示的文件中,并使用内存映射文件来访问数据。我使用例如 50 兆字节的 mmap“视图”(一次将 50 mb 的文件加载到内存中),所以当我有 15 个数据集时,我的进程使用 750 mb 的内存来存储数据。最初是可以的(用于测试),当我有更多数据时,我会以一些速度为代价将 50 mb 调低。

但是,这个启发式现在是硬编码的(我知道我将测试的数据集的大小)。 “在野外”,我的软件需要能够确定要分配的“正确”内存量以最大限度地提高性能。我可以说“我的目标是使用 500 mb 的内存”,然后将 500 除以数据结构的数量以得出 mmap 视图大小。我发现当试图将此“目标内存使用”设置得太高时,虚拟内存管理器磁盘抖动将(几乎)锁定机器并使其无法使用,直到处理完成。在我的“生产”解决方案中要避免这种情况。

所以我的问题,解决问题的方法都有些不同:

  • 单个进程的“最佳”目标大小是多少?我应该尝试最大化我拥有的 2gb(假设 32 位 Win XP 及更高版本,现在非/3GB)还是尝试保持我的进程大小更小,以便我的软件不会占用机器?当我在我的机器上打开 2 个 Visual Studio、Outlook 和 Firefox 时,它们自己很容易使用 1/2 gb 的虚拟内存——如果我让我的软件使用 2 gb 的虚拟内存,交换将严重减慢机器的速度。但是然后我如何确定“最佳”进程大小。

  • 在处理内存映射文件时,我可以做些什么来检查机器的性能?我的应用程序对数据进行了相当简单的数值运算,这基本上意味着它可以快速压缩数百兆字节的数据,从而导致整个内存映射文件(几千兆字节)被加载到内存中并再次非常快速地再次换出一次又一次(想想蒙特卡洛风格的模拟)。

  • 是否有可能不使用内存映射文件而仅使用 fseek/fgets 会比使用内存映射文件更快或更少干扰?

  • 我可以阅读任何关于此的文章、论文或书籍吗?使用“食谱”风格的解决方案或基本概念。

谢谢。

【问题讨论】:

  • 指定 64 位操作系统,问题已解决。
  • 是的,希望我能在几年内做到这一点......
  • @Hans - 今天 64 位和 32 位的渗透率是多少?这似乎是限制性的,也许在 10 年内它会是合理的。
  • @Steve - 这是您从戴尔购买机器时的默认操作系统选择。过去一年左右一直如此。
  • @Hans - 谢谢 - 我不会只在 64 位上建立业务。虽然在这个应用程序的情况下,如上所述,它可能更容易要求。

标签: c++ memory-management


【解决方案1】:

我突然想到,您可以为“太慢”设置一些预定义的阈值,并使用计算机的挂钟即时进行更改。

从保守的低位开始。如果这低于您的“太慢”阈值,请稍微提高下一个文件的大小。反复执行此操作。当您超过阈值时,以迭代方式缓慢地减小尺寸。

【讨论】:

    【解决方案2】:

    我认为这是一个尝试地址窗口扩展的好地方:http://msdn.microsoft.com/en-us/library/aa366527(v=VS.85).aspx

    通过提供滑动窗口,它将允许使用超过 4GB 的内存。缺点是不是所有版本的windows都有。

    【讨论】:

    • 这将要求我的用户获得具有 6 GB 或 8 GB 或 10 GB RAM 的机器,我很乐意满足要求(如上面建议的 64 位机器),但这是不可行的对于我的目标市场。我需要管理软件中的内存问题,我不能扔硬件。
    【解决方案3】:

    最好将内存映射文件的大小固定为系统总内存的某个百分比,并设置最小值。

    请记住,当您访问单个字节时,操作系统将有效地加载整个内存页面,这很可能在后台发生,但只有在顺序数据访问趋于靠近时才会快速。

    因此,您应该尽量保持对数据的顺序访问在内存/文件中尽可能靠近。您还可以查看预加载策略,在实际需要数据之前推测性地访问您的数据。在优化内存缓存效率时,您需要考虑这些因素。

    如果顺序数据访问分散在您的文件中,您最好使用 fseek 和 fread 访问数据,因为这样可以更好地控制何时将哪些数据写入内存。

    还请记住,没有硬性规定。优化有时会违反直觉,因此请尝试各种不同的方法,看看哪些在需要运行的平台上效果最佳。

    【讨论】:

      【解决方案4】:

      我可能不会为此应用程序使用内存映射文件。当您拥有较大的虚拟地址空间(至少相对于您正在处理的数据的大小)时,内存映射文件效果最佳。您映射整个文件,并让操作系统决定哪些部分保持常驻。

      但是,如果您反复映射和取消映射文件的片段(而不是整个文件),您最终可能会通过 fseekfread 读取块来做同样的事情——注意,但是,您希望以这种方式读取单个数据(即,进行一次大读取而不是大量小读取)。

      手动分段内存映射文件可能会获胜的一种方法是,如果您的读取稀疏:如果您只接触到给定文件的 10%。在这种情况下,内存映射意味着操作系统将只读取那些被触摸的页面,而显式读取将加载整个文件。

      哦,我绝对不会花时间试图控制我的资源消耗。操作系统会比你做得更好,因为它知道所有竞争进程。

      【讨论】:

      • 再次阅读您的问题后,我建议您考虑如何交错原始文件,或使用 map-reduce 类型设计分解计算(nb:map-reduce 确实 不需要 需要多台机器)。
      【解决方案5】:

      也许您可以为 Visual Studio 的链接器使用 /LARGEADDRESSAWARE,并为您的进程使用 bcdedit 以使用大于 2GB 的内存。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-06-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多