为什么在4GB内存的系统上,calloc无法分配1GB的空间?

3
我有一个calloc的调用,要求分配1个略大于1 GB的元素。此调用返回了NULL,并且检查errno会显示内存不足错误。然而,在测试期间,我拥有近4 GB的可用物理内存,更不用说可用虚拟内存了。
经过研究,我认为calloc失败的原因可能是没有足够的连续内存。但是,如果我有4GB的可用内存,应该很容易获得约1GB的连续内存。是否有一种方法来检查连续内存的可用性?如果这是问题所在,是否有一种简单的方法来“碎片整理”内存?
还是这与已分配内存的块大小有关,以致实际上它正在尝试分配比可用内存更多的内存?我确定失败原因的选项有哪些?我成功分配这么多内存的选项有哪些?
我使用本机Windows系统,拥有12GB的内存。接下来,我将尝试在虚拟机中运行,并为虚拟机提供几个GB的内存,以检查虚拟机是否可以透明地访问足够的连续内存。如果今天完成了,我会在这里发布结果。

你的Windows系统是32位的,对吧? - Alexander Putilin
3
你需要阅读这篇文章:http://blogs.msdn.com/b/ericlippert/archive/2009/06/08/out-of-memory-does-not-refer-to-physical-memory.aspx。你的电脑正在耗尽*地址空间*,这与RAM没有任何关系。为了更好地理解,建议阅读上述链接。 - Todd Li
@Nya No. 64位Windows(尽管目标平台可能是32位)。 - taz
好的,我已经为您更改了标签。 - Gorpik
1
如果你需要针对32位平台进行开发,请避免依赖于1GB以上的连续地址空间。由于只有2GB-3GB可用,因此很难对地址空间进行碎片整理。请进行一些簿记,并将内存分配到较小的块中。如果可以的话,请针对64位平台进行开发,以避免所有这些麻烦。 - Todd Li
显示剩余3条评论
1个回答

6
让这一点成功的一个重要关键是,确保你的应用程序有1GB的虚拟地址空间可用。在32位Windows应用程序中,默认情况下,一个应用程序最初具有大约2GB的地址空间。
如果在应用程序失败之前进行了许多分配,很可能会切出足够的原始地址空间,使得不再剩下1GB的连续地址空间。一个应用程序只需执行两个小的“战略性位置”分配即可打破地址空间,以至于剩余部分都小于1GB。

那么我该如何检查呢?除了调用calloc()失败之外,还有其他方法吗? - taz
4
使用SysInternals工具vmmap(http://technet.microsoft.com/en-us/sysinternals/dd535533.aspx)来查看Windows进程的虚拟内存映射。请确保启用菜单选项以查看空闲内存,并按大小和类型进行排序。 - Mark Tolonen
@taz:我正在处理一个系统,它会在一开始就分配大约1GB(在32位系统上)的连续内存,然后根据需要使用它。如果我们无法分配整个1GB并且没有遇到任何问题,我们会稍微退缩一下。不过我们必须在一开始就这样做,否则就有可能在面对失败时无法采取任何明智的措施。 - Ed S.
1
我很困惑:如果您有2GiB的虚拟地址空间(因为Windows预留了另外2GiB),那么您只需要一个病态分配就可以了,就在中间吗? - geometrian
@tax: 如果用户应用程序的可用地址空间为0-2^31,则在其中间(2^30)分配几个字节将有效地将地址空间分成两半,每个都小于1GB。实际地址空间从高于0开始,因此默认情况下实际总量会少于2GB。 - Mark Wilkins
显示剩余2条评论

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