我的系统:
物理内存: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相比,大内存分配可能会更容易失败。