将几个大文件映射到内存中

Posted

技术标签:

【中文标题】将几个大文件映射到内存中【英文标题】:Mapping of several big files into memory 【发布时间】:2012-05-04 17:35:14 【问题描述】:

在我们的应用程序中,我们必须能够将多个(即最多 4 个)文件映射到内存中(通过 mapViewOfFile)。很长一段时间以来,这都不是问题,但是随着过去几年文件越来越大,现在内存碎片阻止了我们映射那些大文件(文件大约 200 MB)。如果此时没有加载其他文件,则问题可能已经存在。

我现在正在寻找一种方法来确保映射始终成功。因此,我想在程序启动时只为映射保留一块内存,因此碎片受到的影响要小得多。

我的第一种方法是 HeapCreate 一个私有堆,然后我将 HeapAlloc 一块足够大的内存来保存一个文件的映射,然后使用 MapViewOfFileEx 与该块的地址。当然,地址必须与内存分配粒度相匹配。但映射仍然失败,错误代码为 ERROR_INVALID_ADDRESS (487)。

接下来我用 VirtualAloc 尝试了同样的事情。我的理解是,当我传递参数 MEM_RESERVE 时,我就可以将该内存用于我想要的任何东西,例如映射文件的视图。但我发现这是不可能的(与上面相同的错误代码),直到我再次使用 VirtualFree 完全释放整个块。因此,将不再为下一个文件保留内存。

我已经在使用 低碎片堆 功能,它对我们几乎没有用处。重写我们的代码以仅使用文件的较小视图目前不是一种选择。我也看了这篇 Can address space be recycled for multiple calls to MapViewOfFileEx without chance of failure? 的帖子,但没有发现它很有用,并希望有其他的可能性。

您对我能做什么或我的设计可能有什么问题有什么建议吗? 谢谢。

【问题讨论】:

目前最简单的解决方案是使用 64 位寻址。 @MSalters 这肯定会有所帮助,但与只需要编写一些新函数来正确分配内存的解决方案相比,这意味着更多的工作。加上我们的客户都使用 32 位。不过还是谢谢。 MMF 在 Windows 中被过度使用。它已经通过文件系统缓存对文件进行了非常好的内存映射视图。我不知道你的使用模式,但尝试只使用 ReadFile/SetFilePointer 看看你是否真的减速了。 @HansPassant atm 每段代码都有自己的指向映射的指针,指向对应对象的位置。这些指针就是这样使用的:指向一些内存的指针。所以必须先写一些访问api。但话又说回来,我可能不得不这样做。 那么这些指针就像是整个文件映射的小视图?问题解决了。 【参考方案1】:

好吧,MapViewOfFileEx 的文档很清楚:“建议的地址用于指定文件应在多个进程中映射到同一地址。这要求地址空间区域在所有涉及的进程中都可用. 用于映射的区域不能进行其他内存分配,包括使用VirtualAlloc"

低碎片堆旨在防止相对较小的分配失败。 IE。它避免了 1 个字节的空洞,因此 2 个字节的分配将保持更长时间。按照 32 位标准,您的分配并不小。

实际上,这会很痛苦。如果您真的需要它,请重新实现内存映射文件。所有必要的功能都可用。使用向量异常处理程序在源中分页,并使用QueryWorkingSet 确定页面是否脏。

【讨论】:

我知道MapViewOfFileEx 可用于在进程之间共享内存,但我不知道它是有意的。重新实现内存映射文件确实会受到伤害,因为到目前为止我根本不知道它是如何完成的。我可能需要调查一下。

以上是关于将几个大文件映射到内存中的主要内容,如果未能解决你的问题,请参考以下文章

如何将几个二进制文件合成一个?

将几个表/列放入 CSV 文件

如何将几个rtf文件按序合并

很多小文件还是几个大文件?

内存映射大文件

将几个批处理脚本命令翻译成 python [关闭]