这个问题可能听起来相当简单,但这是我与另一位开发人员的争论。
我小心地在我可以的地方进行堆栈分配,而不是堆分配。他和我说话,看着我的肩膀,并评论说,这是没有必要的,因为他们的表现是一样的。
在我的印象中,增加堆栈是一个常数时间,而堆分配的性能取决于当前堆的复杂性,包括分配(找到合适大小的孔)和反分配(缩小孔以减少碎片,如果我没有弄错的话,许多标准库实现在删除过程中需要时间来做这件事)。
在我看来,这可能非常依赖于编译器。在这个项目中,我特别使用了一个用于PPC架构的Metrowerks编译器。对这种组合的深入了解将是最有帮助的,但一般来说,对于GCC和msvc++,情况如何?堆分配不如堆栈分配高效吗?没有区别吗?还是差异如此之小以至于变成了毫无意义的微观优化。
我想说的是,实际上GCC生成的代码(我还记得VS)不需要做堆栈分配的开销。
对以下函数表示:
int f(int i)
{
if (i > 0)
{
int array[1000];
}
}
下面是生成的代码:
__Z1fi:
Leh_func_begin1:
pushq %rbp
Ltmp0:
movq %rsp, %rbp
Ltmp1:
subq $**3880**, %rsp <--- here we have the array allocated, even the if doesn't excited.
Ltmp2:
movl %edi, -4(%rbp)
movl -8(%rbp), %eax
addq $3880, %rsp
popq %rbp
ret
Leh_func_end1:
所以无论你有多少局部变量(甚至在if或switch内部),只有3880会改变为另一个值。除非你没有局部变量,否则这条指令只需要执行。所以分配局部变量没有开销。
我想说的是,实际上GCC生成的代码(我还记得VS)不需要做堆栈分配的开销。
对以下函数表示:
int f(int i)
{
if (i > 0)
{
int array[1000];
}
}
下面是生成的代码:
__Z1fi:
Leh_func_begin1:
pushq %rbp
Ltmp0:
movq %rsp, %rbp
Ltmp1:
subq $**3880**, %rsp <--- here we have the array allocated, even the if doesn't excited.
Ltmp2:
movl %edi, -4(%rbp)
movl -8(%rbp), %eax
addq $3880, %rsp
popq %rbp
ret
Leh_func_end1:
所以无论你有多少局部变量(甚至在if或switch内部),只有3880会改变为另一个值。除非你没有局部变量,否则这条指令只需要执行。所以分配局部变量没有开销。
通常,堆栈分配只是由堆栈指针寄存器中的减法组成。这比搜索堆快多了。
Sometimes stack allocation requires adding a page(s) of virtual memory. Adding a new page of zeroed memory doesn't require reading a page from disk, so usually this is still going to be tons faster than searching a heap (especially if part of the heap was paged out too). In a rare situation, and you could construct such an example, enough space just happens to be available in part of the heap which is already in RAM, but allocating a new page for the stack has to wait for some other page to get written out to disk. In that rare situation, the heap is faster.