6

免责声明:我为这个问题的冗长道歉(不过我认为这是一个有趣的问题!),但我无法弄清楚如何更简洁地表达它。

对于解决在 64 位 Windows 7 上的 32 位进程中访问多 GB 文件的问题,我已经进行了数小时的研究,从AWE/LARGEADDRESSAWAREVirtualAllocExAWE。我对在 Windows 中编写多视图内存映射系统( 、 等)感到有些自在CreateFileMappingMapViewOfFile但又无法完全摆脱对这个问题有更优雅的解决方案的感觉。此外,我非常了解 Boost 的进程间和 iostream 模板,尽管它们看起来相当轻量级,需要类似的努力来编写仅使用 Windows API 调用的系统(更不用说我已经有内存的事实了——使用 Windows API 调用半实现的映射架构)。

我正在尝试处理大型数据集。该程序依赖于预编译的 32 位库,这就是为什么目前该程序本身也在 32 位进程中运行,即使系统是 64 位的,具有 64 位操作系统。我知道有一些方法可以围绕它添加包装器库,但是,鉴于它是更大代码库的一部分,这确实是一项艰巨的任务。我将二进制标头设置为允许/LARGEADDRESSAWARE(以减少我的内核空间为代价?),这样我每个进程可以获得大约 2-3 GB 的可寻址内存,给予或接受(取决于堆碎片等)。

问题是:数据集是 4+GB,并且运行 DSP 算法,需要对文件进行本质上的随机访问。指向从文件生成的对象的指针在 C# 中处理,但文件本身在 C++ 中加载到内存中(使用此部分内存映射系统)(它是 P/Invoked)。因此,不幸的是,我认为解决方案并不像简单地调整窗口以访问我需要访问的文件部分那么简单,因为本质上我仍然希望将整个文件抽象为一个指针,我可以从中调用方法访问文件中几乎任何位置的数据。

显然,大多数内存映射架构都依赖于将单个进程拆分为多个进程。因此,例如,我将使用 3 个进程访问一个 6 GB 的文件,每个进程都有一个 2 GB 的文件窗口。然后我需要添加大量逻辑来从这些不同的窗口/进程中提取和重组数据。 VirtualAllocEx显然提供了一种增加虚拟地址空间的方法,但我仍然不完全确定这是否是最好的方法。

但是,假设我希望这个程序能够像 64 位系统上的单个 64 位进程一样“轻松”运行。假设我不关心抖动,我只想能够操作系统上的一个大文件,即使任何时候只有 500 MB 加载到物理 RAM 中。有没有什么方法可以在不必手动编写有点荒谬的手动记忆系统的情况下获得此功能?或者,有没有比我迄今为止通过结合 SO 和互联网找到的更好的方法?

这就引出了第二个问题:有没有办法限制这个进程使用多少物理 RAM?例如,如果我想将进程限制为在任何时候仅将 500 MB 加载到物理 RAM 中(同时保持多 GB 文件在磁​​盘上分页)?

对于这个冗长的问题,我感到很抱歉,但我觉得这似乎是对我在 SO 和整个网络上发现的许多问题(只有部分答案)的一个不错的总结。我希望这可以成为一个可以充实明确答案(或至少一些优点/缺点)的领域,并且我们都可以在此过程中学到一些有价值的东西!

4

1 回答 1

2

您可以编写一个访问器类,给它一个基地址和一个长度。如果出现错误条件(超出范围等),它会返回数据或抛出异常(或者您想通知错误条件)。

然后,任何时候你需要从文件中读取,访问器对象可以SetFilePointerEx()在调用之前使用ReadFile()。然后,您可以将访问器类传递给您在读取文件时创建的任何对象的构造函数。然后对象使用访问器类从文件中读取数据。然后它将数据返回给对象的构造函数,该构造函数将其解析为对象数据。

如果稍后您能够编译为 64 位,您可以更改(或扩展)访问器类以改为从内存中读取。

至于限制进程使用的 RAM 量.. 这主要是确保 A)你没有内存泄漏(尤其是淫秽的)和 B)摧毁你现在不需要的对象。即使您稍后会需要它,但数据不会改变......只需销毁对象。然后在您确实需要时重新创建它,允许它从文件中重新读取数据。

于 2013-04-03T20:53:27.930 回答