【发布时间】:2012-03-25 10:07:33
【问题描述】:
我看到很多文章建议不要将大文件映射为 mmap 文件,这样虚拟地址空间就不会被 mmap 单独占用。
在地址空间急剧增加的 64 位进程中,这种情况有何变化? 如果我需要随机访问一个文件,是否有理由不一次映射整个文件? (几十GB的文件)
【问题讨论】:
我看到很多文章建议不要将大文件映射为 mmap 文件,这样虚拟地址空间就不会被 mmap 单独占用。
在地址空间急剧增加的 64 位进程中,这种情况有何变化? 如果我需要随机访问一个文件,是否有理由不一次映射整个文件? (几十GB的文件)
【问题讨论】:
需要注意的一点是,在创建映射时,内存映射需要大块连续的(虚拟)内存;在 32 位系统上,这特别糟糕,因为在已加载的系统上,不太可能长时间运行连续 ram,并且映射将失败。在 64 位系统上,这要容易得多,因为 64 位的上限...很大。
如果您在受控环境中运行代码(例如,您正在构建自己的 64 位服务器环境并且知道可以正常运行此代码),请继续映射整个文件并处理它。
如果您尝试编写可在任何类型的配置上运行的软件中的通用代码,您将需要坚持使用较小的分块映射策略。例如,将大文件映射到 1GB 块的集合,并具有一个抽象层,该层接受诸如 read(offset) 之类的操作,并在执行操作之前将它们转换为正确块中的偏移量。
希望对您有所帮助。
【讨论】:
有理由仔细考虑使用内存映射文件,即使在 64 位平台上(虚拟地址空间大小不是问题)也是如此。它与(潜在的)错误处理有关。
“按常规”读取文件时 - 任何 I/O 错误都会由相应的函数返回值报告。其余的错误处理由您决定。
OTOH 如果在隐式 I/O 期间出现错误(由于页面错误并尝试将所需的文件部分加载到适当的内存页面中) - 错误处理机制取决于操作系统。
在 Windows 中,错误处理是通过 SEH 执行的 - 即所谓的“结构化异常处理”。异常传播到用户模式(应用程序的代码),您有机会正确处理它。正确的处理要求您在编译器中使用适当的异常处理设置进行编译(以保证调用析构函数,如果适用)。
但我不知道在 unix/linux 中如何执行错误处理。
附:我不是说不要使用内存映射文件。我说小心点
【讨论】:
在 64 位上,继续映射文件。
有一点需要考虑,基于 Linux 经验:如果访问是真正随机的,并且文件比您期望在 RAM 中缓存的要大得多(因此再次访问页面的机会很小),那么它是值得的将MADV_RANDOM 指定为madvise 以阻止命中文件页面的不断积累,并且毫无意义地交换其他实际有用的内容。不过不知道windows equivalent API 是什么。
【讨论】: