C ++中的内存分配区域(堆栈与堆与静态)

时间:2013-01-05 14:04:11

标签: c++ linux x86

我知道C ++中有三个而不是两个内存区域:堆栈,堆和静态分配功能的区域。我有两个问题

  1. 为什么堆比堆栈慢得多?当然它应该只是一个额外的间接水平?

  2. 为静态“功能”(变量,函数,类)分配的内存区域是否提供比堆更快的性能?

6 个答案:

答案 0 :(得分:10)

首先是几个旁注。正确的术语是自动的而不是堆栈,动态而不是堆。另一个是使用C ++ 11,现在有四种而不是三种类型的内存。 C ++ 11将线程本地内存添加到组合中。

自动内存很快,因为它是在大多数机器上使用调用堆栈实现的。所需要的是调整堆栈指针正确的数量和瞧!内存已分配。动态内存需要更多的工作。必要的内存可能没有附加到进程,并且要实现这一点需要通过操作系统。即使内存可用,动态内存管理工具仍然必须找到它并将其标记为正在使用。

静态内存被“分配”为编译和链接过程的一部分。在某个源文件中定义静态变量时,编译的代码包含链接器为该变量保留空间的特殊指令。编译器还将您的C / C ++代码转换为机器代码。链接器组合了所有这些不同的数据块和代码,并解析地址以形成可执行的二进制映像。运行程序时,该二进制映像将加载到(虚拟)内存中。一旦程序开始执行,该静态变量的内存就会存在。

就性能而言,最好不要过早担心性能问题。虽然静态内存很快,但存在许多缺点。您要做的最后一件事是将所有数据保持静态。

答案 1 :(得分:3)

  

1)为什么堆比堆栈慢得多?当然它应该是一个额外的间接水平?

因为在堆栈上分配内存意味着通过N增加 1 堆栈指针 sp ,其中N是字节数。以这种方式更改 sp 足够快。使用堆,您可以执行大量操作,例如,查找空闲插槽或请求内存操作系统是昂贵的操作。

1。或者减少,取决于堆栈增长的方式!

  

2)是否为静态"特征"分配了内存区域。 (变量,函数,类)提供比堆更快的性能吗?

如果你的意思是static变量,那么是的,它们比堆快,因为它们是静态分配的,它们一直存在到程序结束。但是,没有static类这样的东西,并且在这种情况下无法比较为函数分配的内存(这个问题对我来说没有任何意义)。

答案 2 :(得分:2)

虽然“堆慢”语句太宽泛而无意义,但与堆分配相关的某些方面肯定比堆慢。与堆栈不同,堆栈由于无法从堆栈中间移除而无法分段,因此堆会受到碎片的影响。您的程序可以按任意顺序取消分配对象,在堆中创建“漏洞”。当您请求更多内存时,分配器必须搜索合适的“漏洞”以满足您的请求。

此外,基于堆栈的操作由计算机硬件高度优化。最后,在自动存储中分配的对象(“堆栈”的官方名称)由于与程序访问的其他本地人的距离较近而被高速缓存的概率较高。

static存储而言,它仅适用于数据成员:静态函数和静态成员函数只是重用关键字而不重用其含义。静态存储中的对象只分配一次,因此没有碎片原因。

分配完成后,三种存储(静态,动态和自动)中对象的访问速度几乎相同。

答案 3 :(得分:2)

比较堆栈,堆或静态分配区域的速度时,有两种不同的速度可供比较。

首先,访问速度。虽然本地(堆栈分配)变量可能略有优势,但这对于编译器在CPU寄存器中缓存更容易,因此这三个区域中的每一个都具有可比性。否则,它基本上只是内存访问。

其次,分配速度。这就是出现巨大差异的地方 静态分配的对象在程序启动时保留其内存(或者当它们驻留在动态加载的库中时,库加载时间),因此就程序而言,它们的分配时间短得多。
堆栈分配的对象分配起来也很便宜,因为它们采用可预测的分配模式(最后分配= =首先解除分配),编译器可以轻松考虑这种模式。例如,如果一个应用程序有多个线程,它也会有多个堆栈(每个堆栈为一个线程保留),因此线程不必相互竞争访问堆栈内存。
堆分配的对象是困难的,因为堆用于不适合早期组的所有内容。此外,整个应用程序通常只有一个堆,因此需要线程同步来从堆中分配内存。并且,由于分配/解除分配模式相当随机,因此必须采取措施以确保不会因堆的碎片而导致堆内存过多丢失。这需要花费一些时间来进行分配或解除分配。

答案 4 :(得分:1)

1)这不是间接问题,而是记忆问题。在堆栈上分配内存只是将堆栈指针向上移动。虽然堆上的分配涉及寻找合适大小的内存,并考虑碎片。

2)静态内存在主入口点之前被分配到程序中,因此没有真正的运行时开销。访问已分配内存的速度并不真正取决于内存的分配位置。

答案 5 :(得分:-1)

堆栈比堆快得多的一个原因是由于局部性原理。存储在堆栈中的数据位于连续的位置,这意味着如果引用一个变量,则其相邻信息将自动带到高速缓存。存储在堆上的数据(动态数组除外)没有这个优势。