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

时间:2013-10-26 17:14:50

标签: java c++ memory stack heap

我只看到了这个缺点:你可以得到StackOverflow :)为什么不只使用堆?

在Java,C,C ++中,函数的参数在堆栈上传递。函数体内的普通变量是在堆栈中创建的。

据我所知,每个线程的堆栈是有限的,有一些默认值,但相对较低:1-8 Mb。 为什么不使用堆而不是堆栈。两者都在内存中,只是操作系统从地址A到B分离是堆,而从C到D是堆栈。

有变量参数。它说有10个变量,每个变量4个字节。如果您阅读11,那么您可能会读取一些“内存”垃圾,也许正是您想要的黑客攻击,或者您可能会遇到分段错误...如果操作系统检测到您是个坏孩子。 :) - 所以安全性不能成为使用Stack的理由。

6 个答案:

答案 0 :(得分:5)

性能是众多原因之一:堆栈中的内存对于预订来说是微不足道的;它没有洞;它可以直接映射到缓存中;它是基于每个线程附加的。

相比之下,堆中的内存是一个的东西;预订比较困难;它可以有洞。

查看this answer(我认为非常好),解释其他一些差异。

答案 1 :(得分:3)

其他人已经提到堆栈可以更快,因为递增/递减堆栈指针的简单性。然而,这与整个故事完全不同。

首先,如果您正在使用压缩堆的垃圾收集器(即大多数现代收集器),则堆上的分配与堆栈上的分配没有太大区别。您只需保持指向已分配和可用内存之间边界的指针,并分配一些空间,您只需移动该指针,就像在堆栈上一样。寿命极短的物体(如大多数功能中的当地人)在GC循环中几乎没有任何成本。保持一个可访问的活动对象需要(一点点)工作,但是一个不再可访问的对象通常只涉及无法工作。

然而,对于大多数变量使用堆栈通常仍然有很大的优势。许多典型的程序倾向于使用几乎恒定的堆栈空间运行相当长的时间段。他们输入一个函数,创建一些变量,使用它们一段时间,将它们从堆栈中弹出,然后在另一个函数中重复相同的循环。

这意味着堆栈顶部的大部分内存几乎总是在缓存中。大多数函数调用都是重用前一个函数调用腾出的内存。通过不断重复使用相同的内存,您最终可以获得更好的缓存使用率。

相比之下,当您在堆中分配项目时,通常最终会为几乎每个项目分配单独的空间。缓存处于“churn”的常量状态,为不再是用户的对象丢弃内存,为新分配的对象腾​​出空间。除非你使用一个微小的堆,否则当它仍在缓存中时重新使用地址的可能性几乎不存在。

答案 2 :(得分:2)

我确信这在网上得到了一百万次回复,但是......

因为您不希望每个方法调用都是内存分配(慢)。所以,你预先分配你的堆栈。

列出here的更多原因(包括安全性)。

答案 3 :(得分:1)

答案是,在堆上分配和取消分配时会出现漏洞。这意味着分配内存变得越来越困难,因为可用的地方大小不同。堆栈仅保留所需的内容,并在您超出范围时将其全部返回。没有麻烦。

答案 4 :(得分:1)

如果所有内容都在堆栈中,那么每次传递这些值时,都必须复制它们。但是,与堆不同,它不需要巧妙地管理 - 堆上的项目需要进行垃圾收集。

因此,他们以两种不同的方式工作,适合两种不同的用途。堆栈是一个快速轻量级的主页,可以在短时间内保存值,而堆允许您在不复制它们的情况下传递对象。

堆栈和堆都不适用于所有场景 - 这就是它们都存在的原因。

答案 5 :(得分:1)

使用堆需要使用new或类似功能从堆中“请求”一些内存。然后,当它完成后,再次delete它。这对于长寿命和/或占用相当大的空间(或占用“编译时未知”空间)的变量非常有用 - 例如,如果从文件中读取变量的字符串,你不一定知道它需要多少空间,从程序中得到一条消息“文件Y中第X行的字符串太大”真的很烦人。

另一方面,堆栈在分配和解除分配时都是“空闲的”(从技术上讲,任何使用堆栈空间的函数都需要一个额外的指令来分配堆栈空间,但是与调用new将涉及的数百或数千,这是不明显的)。当然,class对象仍然必须调用它们各自的构造函数,这可能需要几乎任何时间才能完成,但无论分配存储的方式/位置如何,都是如此。