在64位(或32位)的Windows上,如何在32位进程中访问大于2、3、4GB的文件

6
免责声明:我为这个问题的冗长表示歉意(虽然我认为这是一个有趣的问题!),但我无法想出更加简洁的措辞。
我已经做了数小时的研究,以找到在64位Windows 7上32位进程中访问多GB文件的似乎无数种解决方法,从/LARGEADDRESSAWARE到VirtualAllocEx AWE。我在编写Windows下的多视图内存映射系统方面有些舒适(CreateFileMapping,MapViewOfFile等),但仍然感觉有一种更优雅的解决方案来解决这个问题。此外,我非常了解Boost的interprocess和iostream模板,尽管它们似乎相当轻量级,需要与仅使用Windows API调用的系统编写相同数量的工作(更不用说我已经使用Windows API调用部分实现了具有内存映射体系结构)。
我正在尝试处理大型数据集。该程序依赖于预编译的32位库,这就是为什么目前该程序本身也在32位进程中运行的原因,即使系统是64位,带有64位操作系统。我知道有办法可以在其周围添加包装器库,但鉴于它是更大代码库的一部分,这确实需要一些工作。我将二进制头设置为允许/LARGEADDRESSAWARE(以减少内核空间?),这样我每个进程可以获得大约2-3 GB的可寻址内存,视具体情况而定(取决于堆碎片等)。
问题在于:数据集是4+GB,并且对其运行需要DSP算法,这些算法需要在文件中进行基本随机访问。从文件生成的对象指针在C#中处理,但文件本身在C++中(通过P/Invoke)加载到内存中(使用部分内存映射系统)。因此,我认为解决方案不像简单地调整窗口以访问我需要访问的文件部分那么简单,因为我仍然希望将整个文件抽象成单个指针,从中可以调用方法以几乎任何位置访问数据。
显然,大多数内存映射体系结构依赖于将单个进程拆分为多个进程...因此,例如,我将使用3个进程访问一个6 GB的文件,每个进程持有对文件的2 GB窗口。然后,我需要添加大量逻辑来从这些不同的窗口/进程中提取和重新组合数据。VirtualAllocEx显然提供了一种增加虚拟地址空间的方法,但我仍然不确定这是否是最好的方法。

假设我想让这个程序在64位系统上像单个64位进程一样“轻松”运行。假设我不关心thrashing,只是想在系统上操作一个大文件,即使在任何时候只有500 MB被加载到物理内存中。有没有办法获得这种功能,而无需手动编写相对荒谬的内存系统?或者,是否有比我通过SO和互联网查找到的更好的方法?

这引出了一个次要问题:有没有一种方法限制该进程使用的物理内存量?例如,如果我想将该进程限制为任何时候仅加载500 MB到物理内存中(同时保持多GB文件分页在磁盘上)怎么办?

非常抱歉问题很长,但我觉得它是许多问题(只有部分答案)的一个很好的总结,我在SO和互联网上找到了这些问题。我希望这可以成为一个区别明确的领域(或至少有一些优缺点),我们可以在这个过程中学到一些有价值的东西!


1
如果你只想看结论:Qt可以跨平台处理“大文件”,但在32位平台上不支持内存映射。但它使用内部IO缓存,可能会达到可比较的性能?如果你想使用外部库,请参考以上内容。 - leemes
感谢您的评论,leemes(尽管tl;dr有点粗鲁>_>;;)!我已经研究过使用内部IO缓存,但这似乎会引入相当多的复杂性,而这正是我试图避免的。此外,我想避免将其他库添加到混合中,例如Qt(尽管已经集成了Boost)。 - Kadaj Nakamura
限制RAM,您可以使用Windows作业对象并限制工作集,这将限制物理RAM。不幸的是,我认为这只会最大化交换,所以这可能不是您想要的。我还假设您了解内存映射文件,并且它们不适合您的需求。 - Thomas Weller
1个回答

2
你可以编写一个访问器类,给它一个基地址和一个长度,它返回数据或抛出异常(或以其他方式通知错误条件,例如越界等)。每次需要从文件中读取数据时,访问器对象在调用ReadFile()之前可以使用SetFilePointerEx()。然后你可以将访问器类传递给读取文件时创建的任何对象的构造函数。这些对象随后使用访问器类从文件中读取数据,然后将数据返回到对象的构造函数,解析成对象数据。
如果以后能够编译为64位,你只需更改(或扩展)访问器类来从内存中进行读取。
至于限制进程使用的RAM量... 这主要是确保: A)你没有内存泄漏(尤其是极端情况下的内存泄漏)并且 B)当你不需要某些对象时,就将其销毁掉。即使你稍后还需要该对象,但数据不会更改...也将其销毁。然后在稍后需要时重新创建它,允许它从文件中重新读取数据。

1
嗯...这听起来像是一个有趣的想法,inetknght!感谢您的建议!虽然这听起来像是一种很好的跨文件读取方式,但仍需要添加相当数量的逻辑来手动移动视图到文件上,尽管我同意使用可扩展访问器将是很好的,因为如果这被移向64位,只需修改访问器类即可。如果没有其他易于通过其他结构管理文件的方法,这可能最终成为实现方案。 - Kadaj Nakamura

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接