【发布时间】:2023-04-10 21:25:01
【问题描述】:
- 我记得在我十几岁的时候第一次从我的书中学习记忆处理,下面的例子:
void foo()
{
int a[1000000]; // waste of stack
// ...
}
对
void foo()
{
int* ptr = malloc(1000000 * sizeof(int)); // much better, because the size of stack is limited
// ...
}
(是的,我听说有时编译器可能会将第二个代码优化为第一个)
我一直把堆栈想象成一个“固定的、有限的”内存空间,我的旧书说“堆栈非常小,不要浪费它”,但是堆可以根据需要利用 RAM(限制来自明显的硬件) .
但是:
https://unix.stackexchange.com/questions/63742/what-is-automatic-stack-expansion
Dynamic expansion of the Linux stack
https://www.youtube.com/watch?v=7aONIVSXiJ847:05
那么如果我理解的很好,栈的大小不是我们选择堆的主要原因吗?
好吧,我们仍然需要malloc()/calloc(),因为我们不知道数组大小的编译时间(并且想要避免 VLA)。但是除了这个推理之外,还有什么其他原因将我们的数据实例存储在堆上吗?
我一直认为堆会随着我们malloc() 的增加而扩展。这是正确的吗?
- 我很困惑如果堆栈是动态增长的,那么为什么会发生堆栈溢出?
这是关于虚拟内存中的 Linux 程序的图片:
https://cdn-images-1.medium.com/max/1200/1*8b9-Z3FV6X9SP9We8gSC3Q.jpeg
两个箭头之间的虚拟内存空间耗尽时会发生堆栈溢出?
-
youtube 视频 (https://www.youtube.com/watch?v=7aONIVSXiJ8) 在 47:40 说堆栈扩展可能会导致新分配的页面不会与堆栈的其余部分在物理上连续。新分配的页面将被映射到进程的堆栈中,因此程序的虚拟内存布局保持平坦。我说的对吗?
-
堆向上增长(例如当
malloc()时)。但是,这再次得出结论,堆的大小是有限的(在堆栈之上,在 BSS 底部)。如何通过堆利用整个 RAM?如果低地址为 0,而高地址是 RAM 可用的最高内存地址,我可以对此进行成像的唯一原因。一个进程可能“看到整个 RAM 都可用指针”。这些是虚拟内存地址,因此 CPU 将它们转换为物理地址。我理解的好吗? -
随着我们分配更多堆栈和堆动态增长,我们不必关心使用
brk()手动增加程序中断或使用alloca()函数在堆栈上分配。这些是内核调用的低级函数,我们不直接调用这些函数。这是正确的吗?
如果我理解正确,如果你能回答,我将不胜感激。
【问题讨论】:
标签: linux memory kernel heap-memory stack-memory