这个问题可能听起来相当简单,但这是我与另一位开发人员的争论。

我小心地在我可以的地方进行堆栈分配,而不是堆分配。他和我说话,看着我的肩膀,并评论说,这是没有必要的,因为他们的表现是一样的。

在我的印象中,增加堆栈是一个常数时间,而堆分配的性能取决于当前堆的复杂性,包括分配(找到合适大小的孔)和反分配(缩小孔以减少碎片,如果我没有弄错的话,许多标准库实现在删除过程中需要时间来做这件事)。

在我看来,这可能非常依赖于编译器。在这个项目中,我特别使用了一个用于PPC架构的Metrowerks编译器。对这种组合的深入了解将是最有帮助的,但一般来说,对于GCC和msvc++,情况如何?堆分配不如堆栈分配高效吗?没有区别吗?还是差异如此之小以至于变成了毫无意义的微观优化。


当前回答

前面提到过,堆栈分配只是移动堆栈指针,即大多数架构上的一条指令。将其与堆分配中通常发生的情况进行比较。

操作系统以链表的形式维护部分空闲内存,有效负载数据由指向空闲部分起始地址的指针和空闲部分的大小组成。为了分配X字节的内存,将遍历链表,并按顺序访问每个音符,检查其大小是否至少为X。当找到大小为P >= X的部分时,将P分成大小为X和P-X的两个部分。更新链表并返回指向第一部分的指针。

如您所见,堆分配取决于许多因素,如您请求的内存大小、内存的碎片程度等等。

其他回答

我认为生命期很重要,被分配的东西是否必须以复杂的方式构造。例如,在事务驱动的建模中,您通常必须填写并将带有一堆字段的事务结构传递给操作函数。以OSCI SystemC TLM-2.0标准为例。

在栈上靠近操作调用的地方分配这些资源往往会导致巨大的开销,因为这种构造非常昂贵。好的方法是在堆上分配和重用事务对象,或者通过池或简单的策略,如“这个模块只需要一个事务对象”。

这比在每个操作调用上分配对象快很多倍。

原因很简单,该对象具有昂贵的结构和相当长的使用寿命。

我会说:两种都试试,看看哪种最适合你,因为这真的取决于你代码的行为。

您可以为特定大小的对象编写一个非常高性能的特殊堆分配器。但是,一般的堆分配器性能不是特别好。

我也同意Torbjörn Gyllebring关于对象的预期生命期的观点。好点!

堆栈要快得多。它在大多数架构上只使用一条指令,在大多数情况下,例如在x86上:

sub esp, 0x10

(将堆栈指针向下移动0x10个字节,从而“分配”这些字节供变量使用。)

当然,堆栈的大小是非常非常有限的,因为你很快就会发现你是否过度使用堆栈分配或尝试进行递归:-)

同样,没有什么理由去优化那些不需要它的代码的性能,比如通过分析来证明。“过早的优化”通常会导致比它本身价值更多的问题。

我的经验法则:如果我知道我将在编译时需要一些数据,并且它的大小在几百字节以下,我就会对它进行堆栈分配。否则我进行堆分配。

这不仅仅是堆栈分配更快。您还可以在使用堆栈变量方面获得很多好处。它们有更好的参考位置。最后,折价也便宜得多。

堆栈分配要快得多,因为它所做的只是移动堆栈指针。 使用内存池,您可以从堆分配中获得类似的性能,但这会略微增加复杂性,并带来令人头痛的问题。

此外,堆栈与堆不仅是性能方面的考虑;它还告诉您许多关于对象的预期生存期的信息。