【问题标题】:Realloc() returning NULL when memory is availableRealloc() 在内存可用时返回 NULL
【发布时间】:2016-02-28 00:39:59
【问题描述】:

我有一个在具有 12GB 内存的 Windows 7 机器上运行的 c++ 程序。 编译器和链接器是 Visual Studio 2013 Express。

该程序使用库 OGDF。 我将库源代码编译为具有 Release X64 配置的静态库,并在我的项目中引用了该库。

当我运行问题(调试 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 分配失败?

编辑:

我发现了问题。

当我使用发布配置编译的库文件时,调试器向我显示了错误的局部变量数据。实际原因是库正在调用 realloc(ptr,0)。

【问题讨论】:

  • 你的分页文件有多大?
  • 为什么在 C++ 程序中使用 realoc?你有一个遗留库可以与之交互吗?
  • 你可能在混合堆吗?也就是说,如果您的缓冲区是由调试堆分配的,并且库是为发布而编译的,则每个模块将使用不同的堆。然后,库可能无法重新分配分配在它不管理的堆上的缓冲区。
  • @David Schwartz 页面文件大小是 windows 默认大小,我不记得数字了,也许我明天可以检查一下。但是由于在调用库函数之前我可以成功使用和释放 2.4GB 内存,我可以说有足够的“内存”(RAM+页面文件和 VA 空间)供操作系统提交吗?
  • @eran 我将库编译为静态对象文件(不是 dll)并在我的项目中使用了该库。所以我项目中的realloc 和编译库中的realloc 使用不同的堆并且它们有不同的大小限制?如果这是真的,你知道如何让它们使用同一个堆吗?我检查了 MSDN,有一个关于堆大小 link 的链接器选项,它说“默认堆大小为 1MB”,这也让我感到困惑,因为我可以在不更改链接器选项的情况下分配 GB 的内存,但库代码可以使用

标签: c++ visual-c++ memory realloc


【解决方案1】:

您的问题非常类似于“为什么不给我开一张 500 美元的支票?你银行里有 2,000 美元。”

操作系统在使用内存之前获取内存请求。操作系统不能授予内存分配请求,除非它有足够的后备存储来处理它已经允许的所有请求,无论它们当前是否使用任何 RAM。

例如,如果您malloc 1GB 但尚未访问分配的虚拟地址空间,则该分配将使用少于 1GB 的 RAM。但在该分配被释放之前,系统必须保留 1GB 的后备存储(RAM 或交换),以防您的程序开始使用该分配的空间。

如果系统有太多这样的分配,即使它有足够的空闲 RAM,它也会拒绝新的分配。 Windows 不会过度使用,因为如果这些映射以后需要比操作系统更多的后备存储,则必须强制终止应用程序的风险。

以后避免这些误解的一个好方法是避免单独使用“记忆”这个词。如果您指的是 RAM,请说“RAM”或“物理内存”。如果您的意思是后备存储,请说“后备存储”。如果您指的是地址空间,请说“虚拟内存”。

您会说“我有很多可用内存,所以我应该能够分配内存”。这听起来像个谜。但是,如果您更准确地说,“我有很多空闲 RAM,为什么我不能分配更多的虚拟内存(或支持的内存)?”,您的答案就对了。

【讨论】:

  • 我的 Win8 说页面文件的最小大小是 16MB。如果您的陈述属实,则此合法设置将不允许系统加载。鉴于他提供的数字(64 位,12GB RAM,分配 72MB),我怀疑页面文件是原因。
  • @eran 嗯?我无法理解你的评论。从字面上看,它就像沙拉这个词。 (72MB 分配失败仅意味着操作系统剩余的未保留后备存储少于 72MB。)
  • 我假设“备份存储”指的是页面文件。页面文件可以非常小,与 RAM 的大小无关(不推荐,但合法)。如果每个分配的字节都必须在页面文件中具有匹配的存储空间,那么将页面文件设置为 16MB 将只允许分配 16MB 的内存。胃口大开。
  • 在您谈论 RAM 时,后备存储是指页面文件。但我说的是虚拟内存的分配,而不是 RAM。这些可以由 RAM 或页面文件支持,只要空间未被先前分配保留(无论该分配是否正在使用它)。
  • 他正在编译为 64 位,因此虚拟地址空间肯定不会短缺(除非请求的分配大小与所说的不一样)。如果您指的是总内存消耗接近页面文件 + RAM 大小的情况 - OP 说他有 >4GB 的可用内存;如果这是真的,他应该远离备份存储限制。
猜你喜欢
  • 2012-12-06
  • 2017-06-05
  • 2011-06-14
  • 1970-01-01
  • 2013-11-29
  • 1970-01-01
  • 2021-05-17
  • 2012-08-20
相关资源
最近更新 更多