2

我目前正在编写一个能够处理核心数据的程序。所以我处理的文件大小从 1MB 到 50GB(将来可能更大)。

我已经阅读了一些关于内存映射文件的教程,现在正在使用内存映射文件来管理数据 IO,即从/向硬盘驱动器读取和写入数据。

现在我还处理数据,需要一些与数据大小相同的临时数组。我现在的问题是,我是否也应该为此使用内存映射文件,或者我是否应该在不明确定义内存映射文件的情况下以某种方式让它由操作系统管理。问题如下:

我在多个平台上工作,但总是使用 64 位系统。理论上,64 位虚拟地址空间绝对足以满足我的需要。但是,在 Windows 中,最大虚拟地址空间似乎受到操作系统的限制,即用户可以设置是否允许分页以及允许的最大虚拟内存大小。我还在某处读到,Windows 64 中的最大虚拟内存不是 2^64,而是 2^40 或类似的某个地方,这对我来说仍然足够,但似乎是一个非常奇怪的限制。此外,Windows 有一些奇怪的限制,例如最大大小为 2^31 个元素的数组,与数组类型无关。我不知道这一切是如何在 linux 上处理的,但我认为它的处理方式相似。可能允许的最大虚拟内存=OS-RAM+Swap 分区大小?因此,如果我想使用系统来处理超过内存大小的数据,有很多事情需要解决。我什至不知道我是否可以在 c++ 中以某种方式使用整个 64 位虚拟地址空间。在我的简短测试中,我得到一个编译器错误,无法初始化 mot 超过 2^31 个元素,但我认为,使用 std::vector 等很容易超越这一点。

但是,另一方面,通过使用内存映射文件,它将始终是使用我所有的内存写入操作写入硬盘的数据。特别是对于比我的物理 RAM 小的数据,这应该是一个相当大的瓶颈。还是因为超出了RAM而避免写入直到必须写入?内存映射文件的优势出现在与共享内存或临时通信的进程间通信中,例如我启动应用程序,写一些东西,退出应用程序然后重新启动它,并且只有效地将那些数据读取到我需要的 RAM 中。由于我需要处理整个数据,并且只需要在一个执行实例中使用一个进程,因此在我的情况下这两个优点都没有出现。

注意:作为我的问题的替代解决方案的流式方法实际上并不可行,因为我严重依赖对数据的随机访问。

我理想地想要的是一种方法,我可以独立于它们的大小和操作限制设置限制来处理所有模型,但处理 RAM 中所有可能的情况,并且只有在超出物理限制时,才使用内存映射文件或其他机制(如果还有其他)用于分页超出数据的 RAM,最好由操作系统管理。

最后,处理这些临时现有数据的最佳方法是什么?如果我可以在没有内存映射文件和平台独立的情况下做到这一点,你能给我任何代码片段或类似的东西,并解释它是如何避免这些操作系统限制的吗?

4

2 回答 2

1

由于没有人回答,我将自己更新问题的状态。

今天幸运地接触到 boost 进程间库后,我发现 managed_mapped_file 甚至允许我在映射范围内分配向量,这使得它们几乎和没有映射文件的编程一样容易使用。

此外,我发现:

如果多个进程映射同一个文件,并且一个进程修改了一个映射区域的内存范围,该映射区域也被其他进程映射,则这些更改对其他进程是内部可见的。但是,磁盘上的文件内容不会立即更新,因为这会损害性能(写入磁盘比写入内存慢几倍)。如果用户想要确保文件的内容已经更新,它可以将视图范围内的范围刷新到磁盘。

http://www.boost.org/doc/libs/1_54_0/doc/html/interprocess/sharedmemorybetweenprocesses.html

所以希望它只有在我超过系统物理 RAM 时才开始写入。我还没有进行任何速度测量,并且可能不会进行其中的一些。

我现在可以很好地接受这个解决方案。但是,我将把这个问题留作未回答和打开的状态。在某些时候,有人可能会发现问题并提供更多提示,例如如何防止数据刷新到实际需要的程度,或者有一些其他想法/提示如何处理核心数据之外的数据。

于 2013-09-23T20:42:01.997 回答
0

也许有点晚了,但这是一个有趣的问题。

但是,另一方面,通过使用内存映射文件,它将始终是使用我所有的内存写入操作写入硬盘的数据。特别是对于比我的物理 RAM 小的数据,这应该是一个相当大的瓶颈。还是因为超出了RAM而避免写入直到必须写入?

为避免在有足够内存时写入磁盘,您应该FILE_ATTRIBUTE_TEMPORARY使用FILE_FLAG_DELETE_ON_CLOSE. 这将提示操作系统尽可能长时间地延迟写入磁盘。

至于数组大小的限制:最好提供您自己的数据结构并访问映射视图。对于大数据集,您可能希望使用几个不同(较小)的映射视图,您可以根据需要对其进行映射和取消映射。

于 2015-12-23T14:13:14.720 回答