在C中,当您编写如下代码时:
void some_function(void) {
while (something) {
char buf[4096];
...
}
}
调用函数时是否会发生buf
的分配?或者是否为循环的每次迭代都会进行单独的分配?
如果我将buf
的声明置于循环之外(即函数的开头),是否会有任何性能提升?
答案 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" ;
不明显。在处理实时中断的循环中,它可能是至关重要的。
清晰的代码。尽可能限制可变范围可提高清晰度。表现来自表格设计;没有编码。如果您通过实际测量发现某些特定的编码结构导致事情运行缓慢,那么您可以更改代码。