【问题标题】:Huge memory allocation: stack vs heap巨大的内存分配:堆栈与堆
【发布时间】:2023-03-03 10:15:01
【问题描述】:

我创建了一个需要 1 GB 内存的结构。当我在堆上分配它时,程序启动很快,我在应用程序管理器中看到它的内存使用量达到了这个数量,但是当我像一个简单的变量一样在堆栈上分配它时,应用程序需要更多的时间来启动和在应用程序管理器中,我看到它没有使用那么多内存(只有几 KB)。为什么?这是否意味着建议在堆中存储大量数据?这种情况会更快吗?我知道由于映射等原因,通常在堆栈上分配内存会更快,但在这种情况下,这很奇怪。谁能给我解释一下? 提前致谢!

【问题讨论】:

  • 当你在堆栈上分配它时,你应该得到堆栈溢出。堆栈通常是 1MB 左右...
  • 你究竟是如何在“堆栈上”分配这个的?
  • 这似乎不对。你在什么平台上尝试这个?你试过的代码是什么?您确定您的对象实际上在堆栈上吗?你确定它实际上是一个 GB?
  • Jaa-c:程序刚刚启动,我没有收到任何错误。尼尔:因为我将对象分配为一个简单的变量。 XY; Francois:我正在使用 Windows 和 mingw。
  • 您描述的行为似乎不可能。你能给我们看一些代码吗?

标签: c++ memory heap-memory stack-memory


【解决方案1】:

默认情况下,典型桌面系统的堆栈大小通常约为 1 到几兆字节。在嵌入式设备上可能更少。

如果您分配的内存超出堆栈的容量,操作系统通常会在您尝试访问内存时立即终止程序。

这是否意味着建议在堆中存储大量数据?

对于大数据建议使用free store(动态分配),因为大数据会溢出堆栈。

我看到应用程序管理器没有使用那么多内存(只有几 KB)。

通常,操作系统会在访问内存时为进程分配内存页。由于您的程序没有因堆栈溢出而崩溃,我怀疑您从未访问过内存,因此没有为数据分配内存。

【讨论】:

  • 这个答案是正确的,但没有解决问题中描述的大堆栈分配情况下的奇怪行为。
  • 但这是否意味着由于堆栈大小的限制,我们只能同时分配有限大小的变量?好的,我知道这可能是数十亿,但在这种情况下是有限制的。
  • @EricBlack 完全正确。可用于局部变量的内存量是有限的。比“十亿”更有限。正如我所说,大小通常是一到几兆字节。 Mega 是 百万int 的典型大小为 4。因此,给定一个堆栈为兆字节的进程,您可以在内存不足之前将 262144 个int 变量放入堆栈中。溢出堆栈的最典型方法是:使用大型对象数组,递归深度相对于某些输入线性增加(或更差)。
【解决方案2】:

是的,建议动态进行大量分配 - 因为这样您就可以从容应对失败 (obligatory note on terminology)。

例如,这个:

void might_throw(size_t sz) {
  std::vector<int> v(sz);
  // ...
}

如果在足够大的sz 上失败,将抛出std::bad_alloc,这意味着我可以选择捕获异常并使用较小的数字重试。即使我无法有效地恢复,堆栈展开也可以让我的其他对象安全地清理。

相反

void will_just_die() {
  int a[SomeEnormousConstant];
  // ...
}

如果无法真正创建 a,则没有恢复机制。程序只会崩溃,很难,没有堆栈展开或(标准)错误处理机制。

可能会立即发生,或者它可能仅在您实际尝试访问的a 超出可成功分配的范围时发生。如果你很不走运,它甚至可能看似工作但会破坏其他东西。


给定分配如何在外部显示的细节非常依赖于操作系统,我不确定您使用的是什么 - 应用程序管理器是 OSX 的吗?

直接映射大型动态分配是很常见的,在这种情况下,它会立即显示为虚拟大小的增加,但可能仍然不会分配任何物理页面,除非访问。

如果自动(“堆栈”)分配只是执行帧指针算术并再次依赖于物理页面的延迟分配,这不会影响虚拟或物理大小(同样,直到您尝试实际访问该内存)。

我不知道为什么自动版本需要更长的时间才能启动 - 您必须提供实际上可以重现的 MCVE,以及您的操作系统/平台详细信息才能获得答案.

【讨论】:

  • "将抛出 std::bad_alloc"。不。它可能抛出std::bad_alloc。在过度使用内存的系统上,尽管分配的内存超出了可用的物理内存,它可能不会抛出任何东西。相反,仅在第一次访问时才分配内存,如果没有可用的内存(甚至交换),系统将终止该进程。不幸的是,我认为不可能尝试从此类系统上的过度分配中恢复。
  • 它仍然比自动版本更有可能抛出(并给你恢复的机会) - 无论如何,OOM 杀手可能会终止不同的进程并毕竟给你页面。
猜你喜欢
  • 2011-05-28
  • 1970-01-01
  • 2018-07-24
  • 1970-01-01
  • 2011-10-06
  • 2011-10-09
  • 2013-09-15
  • 2019-05-17
相关资源
最近更新 更多