为什么要使用堆栈而不是堆?

3
我只看到这个的缺点:你可能会遇到StackOverflow :) 为什么不只使用堆呢?
在Java、C和C++中,函数的参数是通过栈传递的。函数体内的普通变量是在栈中创建的。
据我所知,栈对于每个线程都有限制,有一些默认值,但相对较低:1-8 Mb。为什么不使用堆而不是栈呢?两者都在内存中,只是操作系统将地址A到B隔离为堆,将地址C到D隔离为栈。
有可变的参数,它表示有10个4字节的可变参数。如果读了11个,那么你可能会读取一些“内存”垃圾,也许正是你想要的黑客技巧,或者你会得到一个分段错误……如果操作系统把你识别为坏孩子的话。:) 因此,安全不应该成为使用栈的理由。

考虑递归或多线程。 - molbdnilo
6个回答

6

性能是其中一个原因:堆栈中的内存易于管理;它没有间隙;可以直接映射到缓存中;它是基于单个线程附加的。

相比之下,堆中的内存就像一堆东西,更难以管理;它可能有间隙。

请查看此回答(我认为非常好),解释了其他一些区别。


顺带一提,通常堆栈大小比堆小。大对象通常分配在堆上。此外,堆用于具有函数外寿命的对象。 - Thomas Matthews

3

其他人已经提到,由于增加/减少堆栈指针的简单性,堆栈可能更快。然而,这离整个故事还有很长的路要走。

首先,如果您正在使用压缩堆的垃圾收集器(即大多数现代收集器),则在堆上分配与在堆栈上分配并没有太大区别。您只需保留指向分配和空闲内存之间边界的指针,要分配一些空间,只需移动该指针,就像在堆栈上一样。在大多数函数中,生命周期极短的对象(例如本地变量)成本几乎为零。保持活动对象可访问需要(一点)工作,但不再可访问的对象通常涉及几乎没有工作。

然而,对于大多数变量来说,仍然通常使用堆栈具有实质性优势。许多典型的程序倾向于运行相当长的时间,使用几乎恒定的堆栈空间。它们进入一个函数,创建一些变量,使用它们一段时间,从堆栈弹出它们,然后在另一个函数中重复同样的周期。

这意味着堆栈顶部的大多数内存几乎总是在缓存中。大多数函数调用都在重复使用刚刚被前一个函数调用释放的内存。通过持续重复使用相同的内存,您最终获得了更好的缓存使用情况。

相比之下,当您在堆上分配项目时,通常会为几乎每个项目单独分配空间。您的缓存处于不断的“搅动”状态,丢弃您不再使用的对象的内存以为新分配的对象腾出空间。除非使用微小的堆,否则在缓存中仍在使用的地址的重复使用机会几乎不存在。


2

我确定这个问题在网上已经有了无数的回答,但是...

因为你不希望每次方法调用都进行内存分配(很慢)。所以,你需要预先分配好你的堆栈。

这里列出了更多原因(包括安全性)。


如果函数不在堆上分配内存,那么几乎没有任何成本,因为你所做的只是来回移动堆栈指针。只有堆分配才会很慢。 - Bozemoto
@Bozemoto - 难道我不是这么说的吗? - jtahlborn

1
答案是,当你在堆上分配和释放内存时,会产生空洞。这意味着分配内存变得越来越困难,因为可用的位置大小不同。堆栈仅保留所需内容,并在超出作用域时全部返回。没有麻烦。

1
如果所有东西都在堆栈上,每次传递这些值时它们都必须被复制。然而,与堆不同,堆栈不需要聪明地管理 - 堆上的项目需要垃圾回收。
因此,它们以两种不同的方式工作,适用于两种不同的用途。堆栈是一个快速且轻量级的值存储位置,可短暂地保存值,而堆允许您在不复制它们的情况下传递对象。
无论是堆栈还是堆对于每种情况都不完美 - 这就是它们同时存在的原因。

1
使用堆需要从堆中“请求”一定量的内存,使用new或类似的函数。然后,在完成时,再次使用delete。这对于长期存在和/或占用相当多空间的变量非常有用(或者占用“在编译时未知”的空间-例如,如果从文件中将字符串读入变量中,则不一定知道它需要多少空间,而且从程序中得到“第X行文件Y中的字符串太大”的消息真的很烦人)。
另一方面,栈在分配和释放方面都是“免费”的(技术上,使用堆栈空间的任何函数都将需要一个额外的指令来分配堆栈空间,但与涉及数百或数千个调用new的差异不明显)。当然,class对象仍然必须调用其各自的构造函数,这可能需要几乎任意数量的时间才能完成,但无论如何/从哪里分配存储空间,这都是正确的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接