通过将变量设置为静态,我能获得更好的性能吗?

17

为什么有些人会将变量声明为静态的,就像这样:

char baa(int x) {
    static char foo[] = " .. ";
    return foo[x ..];
}

改为:

char baa(int x) {
    char foo[] = " .. ";
    return foo[x ..];
}

这似乎是Linux源代码应用程序中非常常见的。有性能差异吗?如果有,可以有人解释一下原因吗?谢谢。


1
这段代码无法编译,数组指示器应该在变量名之后而不是之前。 - Richard J. Ross III
5个回答

20

这不是为了性能而做的,而是为了减少内存使用。虽然有一定的性能提升,但通常不是你会看到这样的代码的主要原因。

函数中的变量在堆栈上分配,它们将被保留并在每次调用函数时被移除,而且重要的是,它们将计入堆栈大小限制,这对许多嵌入式和资源受限平台来说是一个严重的约束。

然而,静态变量存储在.BSS.DATA段(非显式初始化的静态变量将进入.BSS,静态初始化的静态变量将进入.DATA),并不在堆栈上。编译器也可以利用这一点进行某些优化。


9
在典型的实现中,使用static的版本只会在编译时将字符串放置到内存中的某个位置,而没有用static的版本会在每次调用函数时分配一些堆栈空间,并将字符串写入该空间。
因此,使用static的版本可能:
  • 更快
  • 可能使用更少的内存
  • 将使用较少的堆栈空间(在某些系统上是一种稀缺资源)
  • 与缓存更友好(对于小字符串不太可能是一个大问题,但如果foo是大块内容,则可能会有帮助)。

是的,我做到了。谢谢。我已经编辑了我的答案,使其更加清晰和正确。 - Gareth McCaughan
为什么它会节省内存?加载函数时,它是否仍然需要消耗堆栈内存? - dragonxlwang
@dragonxlwang 请看 char foo[] = "bar"static char foo[] = "bar" 的区别。当程序被加载到内存中时,"bar" 是可执行映像的一部分。区别在于它们的处理方式。static 直接指向已加载的可执行映像中的 "bar"(这也解释了 static 的副作用)。非 static 必须:(1)分配足够大的堆栈空间来存储 "bar",并且(2)在 每次函数调用 时将 "bar" 从已加载的程序复制到该堆栈空间中。每次调用都会在该函数中创建所有堆栈变量的新副本。这也是为什么深度递归会快速耗尽堆栈的原因。 - Jody Bruchon

3

是的,性能是不同的:与自动存储中的变量每次初始化不同,静态变量仅在第一次通过函数时初始化。如果未对foo进行编写,则没有其他区别。如果对其进行编写,那么对静态变量的更改在调用之间保留,而对自动变量的更改则在下一次通过函数时丢失。


2

在方法中定义一个静态变量只是意味着该变量没有“释放”,即它将保留其值以供后续调用使用。这可能会根据算法导致性能提升,但它本身并不是性能提升。


2

如果您将变量声明为静态的,则确实会有所不同:

  1. 首先,内存将分配在bss或数据段中,而不是堆栈中。

  2. 其次,它将仅被初始化一次,而不像函数的其他变量那样每次都会被初始化,这肯定会产生差异。

  3. 第三,它保留在函数调用之间的值。因此,根据情况使用它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接