循环内的堆栈分配

时间:2014-10-24 03:38:37

标签: c memory-management stack

在C中,当您编写如下代码时:

void some_function(void) {
    while (something) {
        char buf[4096];
        ...
    }
}

调用函数时是否会发生buf的分配?或者是否为循环的每次迭代都会进行单独的分配?

如果我将buf的声明置于循环之外(即函数的开头),是否会有任何性能提升?

5 个答案:

答案 0 :(得分:3)

buf在堆栈中some_function的框架中分配。它只在调用some_function时分配一次。所以即使你把buf的声明放在外面,你也不会获得任何性能提升。

但如果你写一些像

这样的话会有所不同
while (...) {
  int a = 5;
}

在循环中。每次迭代都会进行赋值。

答案 1 :(得分:1)

实际上,缓冲区是在循环的每次迭代中分配的。然而,编译器优化,并且在没有初始化器的情况下,它们实际上不会生成代码来执行任何操作以在每次迭代时分配空间;就好像变量是在循环之外声明的那样。在定义中添加初始化,您将看到对性能的影响,因为初始化将在循环的每次迭代中完成。

答案 2 :(得分:0)

在通用处理器(x86,PowerPC,ARM)上的堆栈上分配最多只是一条更改堆栈指针寄存器的指令。这根本不会影响性能(见下面的注释)。此外,编译器也可以为您提升循环外的堆栈分配。底线是增益很小甚至没有。

注意:更改堆栈指针寄存器会在无序处理器中引入指令依赖性。

答案 3 :(得分:0)

C标准允许编译器在每次迭代中分配和释放一次,或者为函数分配和释放一次。在实践中,我见过的每个编译器都为该函数分配,并且这些编译器有很多。然而,即使每次迭代分配一次,差异将是〜2指令向下和向上碰撞堆栈指针(或向上和向下用于向上增长的堆栈)。看到显着的性能差异将是罕见的。

答案 4 :(得分:0)

在您的具体情况下,可能没有性能损失。在最坏的情况下(没有任何优化),分配但是类似于:

 sub sp, #4096

和解除分配就像是

 add sp, #4096

请记住,即使没有优化,对于循环中定义的所有局部变量,也可能只发生一次。如果您有这样的事情:

它很可能被翻译成类似

的东西
 sub sp, #4100
 . . . . 
 add sp, #4100

这样做

void some_function(void) {
    char buf[4096];
    while (something) {
      int x;
    ...
    }
}

对性能没有任何改变。

添加初始化:

void some_function(void) {
    while (something) {
      char buf[4096] = "Something" ;
      int x;
    ...
    }
}

会提高性能。在大多数情况下,开销很小。

但是,将对象置于打开互联网连接的循环中会大大减慢速度。

这是一个平衡问题。对于大多数应用程序,

      char buf[4096] = "Something" ;

不明显。在处理实时中断的循环中,它可能是至关重要的。

清晰的代码。尽可能限制可变范围可提高清晰度。表现来自表格设计;没有编码。如果您通过实际测量发现某些特定的编码结构导致事情运行缓慢,那么您可以更改代码。