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

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

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

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


当前回答

关于这种优化有一个普遍的观点。

您得到的优化与程序计数器实际在该代码中的时间成正比。

如果您对程序计数器进行采样,您将发现它在哪里花费时间,这通常是在代码的一小部分,并且通常是在您无法控制的库例程中。

只有当你发现在对象的堆分配上花费了大量时间时,才会明显地更快地进行堆栈分配。

其他回答

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

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

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

关于这种优化有一个普遍的观点。

您得到的优化与程序计数器实际在该代码中的时间成正比。

如果您对程序计数器进行采样,您将发现它在哪里花费时间,这通常是在代码的一小部分,并且通常是在您无法控制的库例程中。

只有当你发现在对象的堆分配上花费了大量时间时,才会明显地更快地进行堆栈分配。

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

堆栈分配是一对指令,而我所知道的最快的rtos堆分配器(TLSF)平均使用150条指令。此外,堆栈分配不需要锁,因为它们使用线程本地存储,这是另一个巨大的性能优势。因此,堆栈分配可以快2-3个数量级,这取决于您的多线程环境有多严重。

通常,如果关心性能,堆分配是最后的选择。一个可行的中间选项可以是一个固定池分配器,它也只有几个指令,每次分配开销很小,所以它非常适合固定大小的小对象。缺点是它只适用于固定大小的对象,本质上不是线程安全的,并且有块碎片问题。

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

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