我有一台运行在具有12GB内存的Windows 7机器上的c ++程序。 编译器和链接器是Visual Studio 2013 Express。
程序使用库OGDF。 我将库源代码编译成具有Release X64配置的静态库,并在我的项目中引用了库。
当我运行问题(Debug x64配置)时,OGDF库中的代码抛出异常,表明没有足够的可用内存;
E *p = static_cast<E *>( realloc(m_pStart, sNew*sizeof(E)) );
if(p == 0) OGDF_THROW(InsufficientMemoryException);
我暂停程序并打开调试窗口并检查sNew = 9M和sizeof(E)= 8的值,因此它分配了72M内存并失败。
在调试时我打开了Windows任务管理器,它显示我的程序的内存使用量(工作集大小和提交的大小)小于2MB
所以我很困惑为什么REALLOC会因为有足够的可用内存(> 4GB)而失败?即使我的堆中有很多碎片,提交的大小也不到2MB,因此应该有足够的内存。
对于测试建议,我在调用库函数之前插入了以下代码:
void* ddd = malloc(1200000000);
char* b = (char*)ddd;
char ttt = 3;
int g = 0;
for (g = 0; g < 1200000000;++g)
{
*(b + g) = ttt;
}
ddd=realloc(ddd, 2400000000);
b = (char*)ddd;
for (g = 0; g < 2400000000; ++g)
{
*(b + g) = ttt;
}
上面的代码运行正常(调试x64配置),任务管理器显示我的内存使用情况(工作集和提交的大小)在我调用free()之前大约是2.3GB。所以在我的程序中,我可以在堆上分配超过2GB的内存,为什么库代码中的72MB alloc会失败?
编辑:
我发现了问题。
当我使用release-configuration编译库文件时,调试器向我显示了WRONG局部变量数据。实际原因是库调用realloc(ptr,0)。
答案 0 :(得分:2)
你的问题非常类似于“为什么你不给我写一张500美元的支票?你在银行里有2000美元。”
操作系统在使用该内存之前获取内存请求。操作系统无法授予内存分配请求,除非它已为其已允许的所有请求提供足够的后备存储,无论它们当前是否正在使用任何RAM。
例如,如果malloc
1GB但尚未访问已分配的虚拟地址空间,则该分配将使用少于1GB的RAM。但是,在释放该分配之前,系统必须保留1GB的后备存储(RAM或交换),以防程序开始使用该分配的空间。
如果系统有太多这样的分配,即使它有足够的空闲RAM,它也会拒绝新的分配。 Windows不会过度使用,因为如果这些映射后来需要比操作系统更多的后备存储,则必须强行终止应用程序。
将来避免这些误解的一个好方法是避免单独使用“记忆”这个词。如果你的意思是RAM,说“RAM”或“物理内存”。如果你的意思是支持商店,说“支持商店”。如果您的意思是地址空间,请说“虚拟内存”。
你说的话,“我有很多可用内存,所以我应该能够分配内存。”这听起来像个谜。但是,如果你更准确地说,“我有很多可用内存,为什么我不能分配更多的虚拟内存(或支持内存)?”,你会得到答案的一半。