全局变量0初始化惩罚

12

这是一个非常简单的问题:

在运行时,对全局和静态变量进行0初始化是否会有任何性能损失(尽管非常小)?


1
通常,具有静态存储期的变量被放置在可执行文件的.DATA块中,并且在代码生成时将其清零。据我所知,答案是否定的。实际上,我认为这就是具有静态存储期的变量为什么进行零初始化的历史原因 - 因为它没有任何惩罚。 - Rostislav
当你的可执行文件加载到内存中时,具有静态存储期的变量已经存在。不需要进行内存设置。 - Rostislav
@Rostislav,然而,标签是C++ - 所以我认为我们不应该仅限于默认初始化的一个示例。 - SergeyA
惩罚与什么相比?全局和静态变量不是总是被初始化吗? - 463035818_is_not_a_number
在几乎所有的系统中,都有一个区分.data(非零初始化变量)和.bss(零初始化变量)的区别。通常这两个段是紧密相连的,它们被分配在一起,形成了 RAM 的“本地数据”部分。 - Lundin
显示剩余5条评论
2个回答

12
不行,因为C++(和C)标准规定所有未被程序员显式初始化的全局/静态变量必须初始化为零。这些变量被放置在一个特殊的段中,称为.bss。它们在调用main()之前被初始化为零。
如果您显式地将全局/静态变量初始化为值0,则编译器足够聪明以意识到这一点,并仍将其放入bss段中。

您可以通过以下示例进行测试:

#include <stdio.h>

static int uninit;
static int init_zero=0;
static int init_one=1;

int main (void)
{
  printf("%p\n", &uninit);
  printf("%p\n", &init_zero);
  printf("%p\n", &init_one);

  return 0;
}
在这个例子中,变量uninitinit_zero将会在相邻的内存地址结束(很可能离彼此4个字节远),因为它们都在.bss段中。但是,变量init_one将会被分配到另一个位置,因为它被分配在.data段中。

2
标准规定它们必须进行零初始化,但我怀疑.bss段中没有任何内容。因此,在某些架构中可能会在运行时执行零初始化 - 这是正确的吗? - Rostislav
1
顺便提一下,嵌入式系统通常有一个“最小启动”选项,可以完全删除静态存储变量的初始化。这是非标准的,主要用于C应用程序,以实现尽可能快的启动。在C++中,除了静态初始化之外,您还必须执行所有静态存储对象的构造函数,因此您真的希望在调用main()之前通过所有启动代码,否则您的程序可能会出错。实际上,这是C比C ++更快的完美例子 :) - Lundin
通常机制(.BSS)和初始化发生在 main 函数之前这个事实,都无法告诉你是否存在零初始化开销。在传统的 C 系统中,C 运行时库的一部分工作是清空 .BSS(因为它是从具有非零随机内容的操作系统分配的内存)。出于安全原因,现代操作系统可能不允许您分配尚未预清零的页面。可以为这种操作系统编写 C 运行时库,并可能避免清零 .BSS 的开销(因此是最初问题中要求相对开销的原因)。 - JSF
@Lundin:“最小化启动”实际上是编译器工具链的限制标志。这种启动方式只有在您自己明确初始化这些变量时才能起作用,在这种情况下,优化器已经可以删除零初始化。 - MSalters
1
@Yakk,“No”指的是它不会节省任何时间,因为无论如何你都无法避免零初始化。无论编译器如何执行,这都是不可避免的。 - Lundin
显示剩余7条评论

-3

从0初始化的问题(它只是默认初始化的一个子集)扩展到默认初始化,我们仍然可以得出结论,它通常对应用程序性能没有可衡量的影响。然而,很容易设计一个类,在其构造函数中执行数据库查找,从而在应用程序启动期间产生有趣的效果。


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