巨大的内存分配:堆栈与堆
Huge memory allocation: stack vs heap
我制作了一个需要 1 GB 内存的结构。当我在堆上分配它时,程序启动很快,我在应用程序管理器中看到,它的内存使用量达到了那个数量,但是当我将它像一个简单的变量一样分配在堆栈上时,应用程序需要更多的时间来启动和在应用程序管理器中,我看到它没有使用那么多内存(只有几 KB)。为什么?这是否意味着建议将大量数据存储在堆中?那种情况更快吗?我知道通常由于映射等原因,在堆栈上分配内存会更快,但在这种情况下,这很奇怪。谁能给我解释一下?
提前致谢!
在典型的桌面系统上,默认情况下堆栈的大小通常约为一到几兆字节。在嵌入式设备上可能更少。
如果您分配的内存超出堆栈的容量,操作系统通常会在您尝试访问内存时立即终止程序。
Does it mean it's recommended to story big amount of data in the heap?
大数据建议使用free store(动态分配),大数据会溢出栈。
Application Manager i saw it is not using that amount of memory (just few KBs).
通常,操作系统会在访问内存时为进程分配一页内存。由于你的程序没有因为堆栈溢出而崩溃,我怀疑你从未访问过内存,因此没有为数据分配内存。
是的,建议动态进行大量分配 - 因为这样您就可以优雅地应对失败 (obligatory note on terminology)。
例如,这个:
void might_throw(size_t sz) {
std::vector<int> v(sz);
// ...
}
将抛出 std::bad_alloc
如果它因足够大的 sz
而失败,这意味着我可以选择捕获异常并使用较小的数字重试。即使我不能有效地恢复,堆栈展开也可以安全地清理我的其他对象。
反之
void will_just_die() {
int a[SomeEnormousConstant];
// ...
}
如果 a
无法真正创建, 没有恢复机制。该程序将崩溃,严重,没有堆栈展开或(标准)错误处理机制。
这 可能 立即发生,或者它可能仅在您实际尝试访问比成功分配更多的 a
时发生。如果您非常不幸,它甚至可能 看起来 可以工作,但会破坏其他东西。
给定分配如何在外部显示的详细信息非常 OS 相关,我不确定您使用的是什么 - Application Manager 是 OSX 吗?
直接映射大型动态分配是很常见的,在这种情况下,它会立即显示为虚拟大小的增加,但可能仍未分配任何物理页面,除非在访问时。
如果自动 ("stack") 分配只是执行帧指针算法并再次依赖物理页面的惰性分配,这不会影响虚拟或物理大小(同样,直到您尝试实际上正在访问该内存)。
我不知道为什么自动版本需要更长的时间才能启动 - 你必须提供一个 MCVE 实际上可以重现的,以及你的 OS/platform 详细信息得到答案。
我制作了一个需要 1 GB 内存的结构。当我在堆上分配它时,程序启动很快,我在应用程序管理器中看到,它的内存使用量达到了那个数量,但是当我将它像一个简单的变量一样分配在堆栈上时,应用程序需要更多的时间来启动和在应用程序管理器中,我看到它没有使用那么多内存(只有几 KB)。为什么?这是否意味着建议将大量数据存储在堆中?那种情况更快吗?我知道通常由于映射等原因,在堆栈上分配内存会更快,但在这种情况下,这很奇怪。谁能给我解释一下? 提前致谢!
在典型的桌面系统上,默认情况下堆栈的大小通常约为一到几兆字节。在嵌入式设备上可能更少。
如果您分配的内存超出堆栈的容量,操作系统通常会在您尝试访问内存时立即终止程序。
Does it mean it's recommended to story big amount of data in the heap?
大数据建议使用free store(动态分配),大数据会溢出栈。
Application Manager i saw it is not using that amount of memory (just few KBs).
通常,操作系统会在访问内存时为进程分配一页内存。由于你的程序没有因为堆栈溢出而崩溃,我怀疑你从未访问过内存,因此没有为数据分配内存。
是的,建议动态进行大量分配 - 因为这样您就可以优雅地应对失败 (obligatory note on terminology)。
例如,这个:
void might_throw(size_t sz) {
std::vector<int> v(sz);
// ...
}
将抛出 std::bad_alloc
如果它因足够大的 sz
而失败,这意味着我可以选择捕获异常并使用较小的数字重试。即使我不能有效地恢复,堆栈展开也可以安全地清理我的其他对象。
反之
void will_just_die() {
int a[SomeEnormousConstant];
// ...
}
如果 a
无法真正创建,没有恢复机制。该程序将崩溃,严重,没有堆栈展开或(标准)错误处理机制。
这 可能 立即发生,或者它可能仅在您实际尝试访问比成功分配更多的 a
时发生。如果您非常不幸,它甚至可能 看起来 可以工作,但会破坏其他东西。
给定分配如何在外部显示的详细信息非常 OS 相关,我不确定您使用的是什么 - Application Manager 是 OSX 吗?
直接映射大型动态分配是很常见的,在这种情况下,它会立即显示为虚拟大小的增加,但可能仍未分配任何物理页面,除非在访问时。
如果自动 ("stack") 分配只是执行帧指针算法并再次依赖物理页面的惰性分配,这不会影响虚拟或物理大小(同样,直到您尝试实际上正在访问该内存)。
我不知道为什么自动版本需要更长的时间才能启动 - 你必须提供一个 MCVE 实际上可以重现的,以及你的 OS/platform 详细信息得到答案。