【问题标题】:How to read large file on computer with limited RAM under Windows 7? The file size is 25GB but RAM capasity is 16GB only如何在 Windows 7 下在 RAM 有限的计算机上读取大文件?文件大小为 25GB,但 RAM 容量仅为 16GB
【发布时间】:2014-09-05 04:26:33
【问题描述】:

我需要开发一个应用程序来读取包含俄罗斯高速公路图的文件。根据文件的内容,应用程序必须检测两个指定城镇之间的最短路径。应用程序必须用 C++ 中的非托管代码编写。我需要在 MS VS 2013 中将此应用程序开发为没有 MFC 支持的 C++ 控制台应用程序。客户计算机上装有 Windows 7 操作系统。作为搜索引擎 - 必须使用“A*”算法。我的问题如下。包含高速公路图的文件大小为 25GB,但客户计算机上的 RAM 容量仅为 16GB,没有机会扩展它。在这种情况下,我可以使用非托管 C++ 的任何编程技术来处理大文件吗?我想到了读取文件的大小大于计算机上的 RAM 容量的情况。在这种情况下,我应该以何种方式设计应用架构?

【问题讨论】:

  • 只要是 64 位操作系统上的 64 位程序,就可以了。虚拟内存将自动启动。虽然性能会很慢。理想情况下,您会将问题分解为子问题,这些子问题都将单独使用更少的内存。
  • 您的 25 GB 文件包含的信息可能比计算 A 和 B 之间最短路径所需的信息多得多。也许在读取该文件时简化该文件中的信息是一种选择。
  • 你总是可以设计一个垃圾收集的块管理器,它会按需流入块,虚拟化你的文件访问,并且在一段时间不被访问后,块将被取消分配......
  • 各位,我的客户有一台带有 32 位操作系统的 32 位计算机。请原谅我,但我忘了在问题中写下这个细节。
  • 谁能告诉我如果我为 MapViewOfFile() 的第 3、第 4 和第 5 参数分配 0 的值以获得 25GB 文件的完整保护,所以可以使用保护in application会很慢吗?

标签: c++ windows unmanaged filesize


【解决方案1】:

您必须在文件句柄上调用 CreateFileMapping,然后在映射句柄上调用 MapViewOfFile。它非常方便,允许您在不读取文件的情况下访问整个文件。在这种情况下,您的目标必须是 64 位...

【讨论】:

  • 这肯定行得通,但性能将受磁盘 IO 速度和文件上数据的空间性质的影响——如果它在一个很小的物理范围内,它将全部被分页一起放入内存中的性能应该不错,但如果您的图形算法和数据布局导致大量间隔很大的随机 IO,您可能会颠簸磁盘并且运行速度非常慢。
  • +1 FileMap 是一个可行的解决方案,请参阅我的问题stackoverflow.com/questions/2171625/…
  • Malkocoglu 写了有关 CreateFileMapping 和 MapViewOfFile 调用的文章。但它只有在64位计算机的情况下才能成功。但是32位电脑的情况呢?
  • 您的文件太大,无法为 32 位进程映射。 32 位指针无法寻址 25 GB 的文件缓冲区!
  • 可能 - 是的。受益于我检查关于 FileMap 的建议,正如 Jichao 所说。
【解决方案2】:

使用std::readline,您可以一次读取一行文件。 640 kB RAM 就足够了 ;)

我很确定它是一个文本文件,甚至可能是 XML。在这种情况下,您将使用专用的“SAX”XML 解析器。我知道这不是二进制的,因为我知道您可以将整个欧洲地图(高速公路和所有次要道路)放入 8 GB 以下。

顺便说一句,A* 已过时。 ArcFlags 等现代路由算法要快得多。

【讨论】:

  • 这更像是一个评论而不是一个真正的答案,不是吗?如果您一次阅读一行,则必须等待很长时间才能找到您的路线;-) 但是非常感谢您提到 ArcFlags (i11www.iti.uni-karlsruhe.de/_media/teaching/theses/files/…),这确实可以帮助我们的俄罗斯朋友:它使用较小的预计算分区全局图和这些都受内存处理的影响!
  • 我需要构建(或设计)应用程序架构,以防磁盘上的文件大于计算机的 RAM。这是我的第一个问题!让我在搜索中保持“A*”。
  • 当图形文件非常大(如我的情况)并且其大小大于 RAM 容量时,有人可以根据应用程序设计的架构给我建议吗?
  • @user3769902:如前所述,在读取文件时对其进行解析,您将不需要 25 GB 的内存。
【解决方案3】:

嗯...为什么不只是小部分读取文件呢?可以说,文件中的 128 条记录。 你可以创建一些类,它会隐藏在这个机制中,所以程序的其他部分不会承认完全加载和这个方法之间的区别。 其他方式 - 将文件映射到内存。

顺便说一句,你是俄罗斯人吗?

【讨论】:

  • 是的,我是。我是俄罗斯人。我住在萨马拉,这是伏尔加河左岸的城市。
  • 您要记住按 128 条记录部分读取文件。但在这种情况下,每个部分都必须包含有关当前节点的直接邻居的信息。从问题节点到目标节点的路径成本定义需要“A*”。
【解决方案4】:

您的问题非常广泛!您将面临的主要问题是加载/卸载数据块会使您的搜索变得非常缓慢,尤其是如果相邻节点位于不同的块中。

由于您的图表是真实世界的地理,您的 A* 启发式肯定会是数学距离 btw 点。这意味着您的算法将倾向于主要根据与目标的距离来开发路径,您可以使用它来优化加载/卸载:

这里有一些提示:

  • 如果您可以通过按地理方格对数据进行分组来组织数据文件,您至少可以减少一点加载/卸载成本。

  • 考虑每个方格的 fil 偏移量的内存索引,以便您可以更快地访问要加载的新块。

  • 您还可以将此方法与缓存相结合。与其将大方块加载到最大大小的一块中,不如将较小的方块加载到您使用缓存算法管理的几个较小的内存块中(最近最少使用的被卸载):由于不需要许多地理区域,它们将被最常替换使用的节点(即高速公路周围的节点)。

  • 稍加创意,您或许还可以稍微偏离标准 A*,通过添加一点“喜气洋洋”:与其总是采用最佳扩展路径,不如考虑到它有时可能是更有效地扩展保留在同一内存块中的路径。

【讨论】:

  • 如果我指定(在 MapViewOfFile 调用中)在进程地址空间中投影一个完整的 25GB 文件(如果可能的话),这会大大减慢应用程序的工作速度吗?
  • 使用 MapViewOfFile(),系统使您的文件可以通过虚拟内存访问。它将通过内存分页管理访问,换入和换出不太需要的页面(如缓存算法的块)。但是,如果您的文件没有组织以利用地理知识,则 MapView 将不得不进行比需要更多的换入和换出。你应该看看这个:stackoverflow.com/questions/1880714/…
【解决方案5】:

不确定这是否仍然是一个悬而未决的问题,刚刚看到这个问题。

32 位应用程序完全能够读取/写入大于 4GB 的文件。

您甚至不需要为其创建文件映射,除非您绝对必须拥有(相当于)数据的内存表示。如果是这种情况,它会做更多的工作,但仍然可行(您可以创建一个类来包装文件的映射视图并将数据“分块”成适合您可用地址空间的大小)。正如其他人所指出的,您不能同时映射大于地址空间的文件。此外,之前的答案/cmets 中关于性能考虑的 cmets 和警告也适用。

几个问题:文件是如何被索引的(如果是的话)?如果有索引,您能否发布索引布局和记录的示例?即使没有索引,您也可以创建自己的索引并通过包装类访问记录。你能发布一个个人记录的例子吗?

如果您不需要内存中的表示,一个更好的选择 - 当然从性能的角度来看 - 将是创建一个处理读取/写入文件的类并使用SetFilePointerEx在任何读取之前进行搜索.如果文件具有适合可见地址空间的索引,您甚至可以将文件的该部分映射到内存中,并根据需要对单个记录(未映射)进行查找/读取。更复杂的方法还可以在 MRU(或其他)基础上处理缓存记录以帮助提高性能。

【讨论】:

    猜你喜欢
    • 2016-12-13
    • 1970-01-01
    • 1970-01-01
    • 2018-09-08
    • 1970-01-01
    • 2015-03-29
    • 2020-10-30
    • 1970-01-01
    相关资源
    最近更新 更多