最大内存映射分配大小?

7

我的系统:
物理内存:3gb
Windows XP Service Pack 3 (32位)
交换文件大小:30gb

目标:在我的计算机上找到可以分配的最大内存映射大小。

当我运行下面的代码来分配2gb的内存映射文件时,调用失败了。

handle=CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE|SEC_COMMIT,0,INT_MAX,NULL);

我一直感到很困惑,因为我可以通过不断地使用每次100mb调用CreateFileMapping来分配一个内存映射文件的大小,直到达到系统交换文件大小的30gb。

重启计算机后,再次运行请求创建2gb内存映射文件的应用程序,它可以返回有效的句柄。这让我有点困惑,到底Windows在干什么呢?

所以情况是这样的,我可以创建许多小的内存映射文件,占用所有的系统页面文件(30gb),但是当请求单个2gb的分配时,调用会失败。重启计算机并运行相同的应用程序后,调用成功!

一些注释:
1) 内存映射文件还没有被加载到进程的虚拟地址空间中,文件没有视图。
2) 操作系统可以将小的100mb内存映射文件分配给30gb的系统页面文件!

现在我能得出的唯一结论是,Windows XP SP3 (32位)虚拟内存管理器无法成功地在系统页面文件中保留所请求的2gb,并因系统内存碎片而失败(似乎它需要保留连续的内存分配,即使每个页面文件只有4kb)。重启后,我假设系统内存碎片较少,从而允许同样的调用成功并分配大小为2gb的内存映射文件。

我进行了一些实验,在运行机器一整天之后,我启动了一个小应用程序来分配300mb的内存映射文件,然后释放它。然后它会将大小增加1mb并再次尝试。最终停在700mb处并报告(资源不足)。我接着关闭每个应用程序,这样就停止了错误消息,最终可以分配一个大小为3.5gb的内存映射文件!

那么我的问题是,这里到底发生了什么?虚拟内存管理器内部必须发生某种类型的内存碎片,因为分配100mbs的内存映射文件会消耗高达系统页面文件(commit limit)的30gb。

更新
结论是,如果您要创建一个由系统页文件支持的大型内存映射文件,并使用INVALID_HANDLE_VALUE,那么系统页文件(交换文件)需要调整大小到所需大小,并处于非碎片状态以处理大内存分配(> 2GB)!但在重载IO的情况下,仍可能失败。为了避免所有这些问题,您可以创建所需大小的文件(我创建了1TB),并将其内存映射到该文件。
最终更新
我在Windows 7上运行了同样的测试,并惊讶地发现每一次都能成功(直到系统页文件大小),而不需要任何额外的操作。因此我认为这只是一个错误,即在Windows XP上,与Windows 7相比,大内存分配可能会更容易失败。

我唯一能得出的结论是,用于存储2GB的4KB页面文件的表太大了,超出了系统内存的处理能力,导致失败。 - Chad
这是一个谜。无论您的虚拟和物理内存有多大,无论您运行多少个进程,您都无法在32位Windows上创建大于约300MB的内存映射文件。 - Gene Bushuyev
3个回答

5
问题是文件碎片化。物理内存(RAM)与此无关。在虚拟内存系统中,“内存”是从文件系统分配的。物理内存只是加速访问内存的优化。
当您请求具有写访问权限的内存映射文件时,系统必须有一个具有连续页面的空闲文件。系统交换文件经常会出现碎片。如果您的磁盘驱动器已经很好地进行了碎片整理,则应该能够使用您选择的文件(而不是系统页面文件)创建一个大型内存映射文件。
因此,如果您真的需要一个2GB的内存映射文件,则需要在安装时在驱动器上创建一个。这将把创建一个连续的2GB文件的问题转移到安装过程中,但一旦创建,您应该就可以了。

整理系统页面文件,告诉你进展如何。 - Chad
成功创建了22,743mb的映射。 - Chad
问题Tergiver。在重负载IO或操作系统的正常使用下,我的分配可以从20GB降至仅6GB,有时甚至降至300MB。我猜测Windows虚拟内存管理器已经将页面放入系统页文件中,破坏了它找到连续空闲页面的能力。尽管在运行重负载IO程序后等待30分钟,我可以再次重新分配20GB。有什么想法吗?我猜Windows需要时间卸载这些页面。 - Chad
请记住,系统页面文件代表所有虚拟内存。当您调用malloc并增加堆时,您正在分配系统文件中的页面。即使物理内存可用于分配,也必须为其分配页面文件中的后备页面。操作系统不断运行程序,这些程序不断分配和释放内存。最终,事情可能会“平静下来”,分配的内存(由页面支持)将减少... - Tergiver
嗯,我只是好奇VMM是否像垃圾收集器一样碎片整理页面文件?因为在七个小时的正常使用后,我最多只能获取5GB,而机器刚开始时可以获取20GB。承诺的内存为400MB。所以我很好奇碎片是否会留在那里。我的假设是任何服务或守护程序都可能请求内存,从而将页面放入页面文件中,以防止获取所需的连续页面。不过,看到页面存储在页面文件中的位置会很酷! - Chad
显示剩余3条评论

3
所以我的问题是这里发生了什么?内部虚拟内存管理器必须发生某种类型的内存碎片化,因为分配100MB的内存映射文件将消耗高达30GB的系统页面文件(提交限制)。
听起来很合理。如果您不需要大块连续的内存,请勿请求它们,如果您可以获得相同数量的较小块的内存。
要找到我可以在我的机器上分配的最大内存映射大小。
- 使用大小X进行尝试。 - 如果失败,请使用大小X/2并重复。
这样可以在运行时获取一个块,也许不是确切的最大可能块,但在2的因素内。

我的第一个想法是虚拟地址空间的碎片化。然而,在这里它不应该起作用,因为还没有涉及到虚拟地址 - 只有在映射视图时才分配它们。那么它可能是什么其他的碎片化呢? - Suma
是的,这是一种有效的方法,但我更好奇的是为什么会失败?因为它将被保留在系统页面文件中,这是什么原因导致调用失败?是由于系统内存碎片化吗?我唯一能得出的结论是,用于保存2GB 4KB页面文件的表对于系统内存来说太大了,所以它失败了。 - Chad

0

让我们来看一下Windows开发人员的职位。 假设某个用户执行以下步骤:

  1. 创建内存映射。
  2. 填充一些敏感数据的内存
  3. 从文件中取消映射
  4. 继续使用内存
  5. Windows需要卸载这些页面以进行关键任务。

解决方案-映射内存应适合交换。但这并不意味着映射将被交换。


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