使用内存映射文件读取大文件

Saa*_*aar 7 windows memory-management

我看到许多文章建议不要将大文件映射为mmap文件,因此虚拟地址空间不会仅由mmap完成.

在地址空间急剧增加的64位进程中,这有何变化?如果我需要随机访问文件,是否有理由不立即映射整个文件?(几十GB的文件)

tim*_*day 6

在64位上,继续并映射文件.

有一点需要考虑,基于Linux的经验:如果访问是真正随机的,并且文件比你在RAM中缓存的要大得多(因此再次点击页面的机会很小)那么值得指定MADV_RANDOMmadvise停止积累命中文件页面,毫无意义地交换其他实际有用的东西.不知道windows等效API是什么.


val*_*ldo 5

即使在64位平台(虚拟地址空间大小不成问题)上,也有必要仔细考虑使用内存映射文件的原因。它与(潜在的)错误处理有关。

“常规”读取文件时-相应的函数返回值报告任何I / O错误。其余的错误处理取决于您。

OTOH,如果在隐式I / O期间发生错误(由于页面错误而导致,并尝试将所需的文件部分加载到适当的内存页面中)-错误处理机制取决于操作系统。

在Windows中,错误处理是通过SEH执行的-所谓的“结构化异常处理”。异常传播到用户模式(应用程序的代码),您可以在其中正确处理它。正确的处理要求您在编译器中使用适当的异常处理设置进行编译(以确保调用析构函数(如果适用))。

我不知道如何在unix / linux中执行错误处理。

PS我不说不使用内存映射文件。我说要小心点

  • @David Heffernan:不完全是,这取决于您正在阅读的内容。如果加载程序代码或数据(全局,堆栈/ tls或堆)时出错,则该过程刚刚终止。操作系统没有为应用程序提供处理此问题的机会,因为该应用程序已“损坏”。由应用程序代表自己创建的内存映射文件引起的OTOH错误-有更多机会正确处理 (3认同)
  • @David Heffernan:当然。操作系统不知道您在“读取一个哑指针”。从它的角度来看,您尝试取消引用不可访问的虚拟地址,它引发异常,并且您的应用程序有机会处理它。是bug还是合法条件-由应用程序决定。我同意,它与“一次或逐个映射整个文件”这个问题正交。我以为问题是制图与其他选择 (2认同)

Riy*_*lla 2

需要注意的一件事是,在创建映射时,内存映射需要大的连续(虚拟)内存块;在 32 位系统上,这尤其糟糕,因为在已加载的系统上,不可能长时间运行连续内存,并且映射将会失败。在 64 位系统上,这要容易得多,因为 64 位的上限非常大。

如果您在受控环境中运行代码(例如,您正在构建自己的 64 位服务器环境,并且知道如何运行此代码),请继续映射整个文件并处理它。

如果您尝试编写可以在任意数量的配置类型上运行的软件中的通用代码,您将需要坚持较小的分块映射策略。例如,将大文件映射到 1GB 块的集合,并具有一个抽象层,该抽象层接受诸如read(offset)之类的操作,并在执行操作之前将它们转换为正确块中的偏移量。

希望有帮助。