0

这个问题是关于堆栈溢出的,所以问这里比这里更好。

如果我们考虑如何在 unix 中为程序 (a.out) 使用内存,它是这样的:

| etext | stack, 2mb | heap ->>>

几年来我一直想知道为什么堆栈有 2MB 的限制。考虑到我们有 64 位的内存地址,那么为什么不这样分配:

| MIN_ADDR                                                              MAX_ADDR|
| heap ->>>>                                                 <<<- stack | etext |

MAX_ADDR 将在 2^64 附近,而 MIN_ADDR 在 2^0 附近,因此程序可以使用许多字节,但内核不一定会考虑(通过实际为它们分配页面)。堆和堆栈可能永远不会相互到达,因此不需要 2MB 的限制(而是有 ~1.8446744e+19 字节的限制)。如果我们害怕它们会互相影响,那么将限制设置为 2^63 或一些奇怪而巨大的数字。

此外,堆从低到高增长,因此我们的内核仍然可以调整内存块的大小(例如使用 malloc 分配),而不必移动内容。

此外,在某种程度上,堆栈帧的大小始终是静态的。所以我们永远不需要在那里调整大小,如果我们这样做,那无论如何都会很尴尬,因为我们还需要更改return使用的整个指针结构并由call创建。

我将此作为另一个stackoverflow问题的答案阅读:

“我的直觉是这样的。栈不像堆那么容易管理,栈需要存储在连续的内存位置。这意味着你不能根据需要随机分配栈,但你至少需要保留虚拟用于该目的的地址。保留的虚拟地址空间的大小越大,您可以创建的线程就越少。

来源:为什么Linux(x86)的页面大小是4 KB,这是如何计算的

但是我们有大量的内存地址!所以这没有任何意义。那么为什么是 2MB 呢?

我问的原因是,就悬空指针和内存泄漏而言,在堆栈上分配内存是非常安全的:

例如我更喜欢

int foo[5];

代替

int *foo = malloc(5*sizeof(int));

因为它会自行释放。此外,堆栈上的分配比 malloc 执行的分配更快。但是,如果我在堆栈上分配一个图像(即 jpeg 或 png),我就处于堆栈溢出的危险区域。

关于这件事的另一点,为什么不也允许这样做:

int *huge_list_of_data = malloc(1000*sizeof(char), 10 000 000 000*sizeof(char))

我们分配了一个列表对象,它最初的大小为 1KB,但我们要求内核分配它,以便放置它的页面不用于其他任何东西,并且我们希望在它后面有 10GB 的页面,必要时可以(部分)交换。

这样我们就不需要 10GB 的内存,我们只需要 10GB 的内存地址

那么为什么不:

void *malloc( unsigned long, unsigned long );

?

本质上:为什么不使用 UNIX 的分页系统来解决我们的内存分配问题?

感谢您的阅读。

4

0 回答 0