【问题标题】:What run-time costs are there to initializing a static with a variable value?使用变量值初始化静态变量有哪些运行时成本?
【发布时间】:2012-07-10 13:42:02
【问题描述】:

在 C++ 中,合理的编译器使用变量值而不是常量值初始化静态变量的预期运行时成本是多少?

例如考虑以下代码:

bool foo();
bool baz1() {
  const bool value = foo();
  static bool alternate1 = value;
  static bool alternate2 = false;

  // Do something.
  return alternate1;
}

alternate1alternate2 之间的预期运行时成本差异是多少?

【问题讨论】:

  • 这真的是性能瓶颈吗?

标签: c++ static initialization runtime


【解决方案1】:

从编译时常量(备选方案 2)初始化很可能发生在程序启动期间,每次调用函数时都没有成本。

局部静态变量的线程安全初始化将导致编译器生成类似这样的伪代码:

static bool alternate1;

static bool __initialised = false;
static __lock_type __lock;
if (!__initialised) {
    acquire(__lock);
    if (!__initialised) {
        alternate1 = value;
        __initialised = true;
    }
    release(__lock);
}

因此,每次调用函数时都可能需要对标志进行测试(可能涉及内存屏障或其他同步原语),以及第一次获取和释放锁的进一步成本。

请注意,在您的代码中,每次都会调用foo(),无论变量是否已初始化。如果您将初始化更改为

,它只会在第一次被调用
static bool alternate1 = foo();

细节当然取决于实现;这是基于我对 GCC 生成的代码的观察。

【讨论】:

  • 我确实需要总是调用 foo()。
【解决方案2】:

static 变量在程序开始时被初始化,这意味着初始化只会发生一次。仅一个布尔值的成本非常低,对于您的 alternate1 将是执行 foo() 的成本,在您的示例中并不多,因为它只是一个空函数。

概括地说,成本将是初始化基本类型(int、float 等)或任何用户定义类型/库定义类型的初始化(运行 ctor)的最大成本。任何用函数初始化的static,那么最大值将是正在执行的函数的成本。

【讨论】:

  • 在函数内部声明的静态变量在控制第一次到达它们时被初始化,并且初始化必须是线程安全的,因此会有一些相关的成本。
  • 初始化部分是不是用词不当?它是和编译好的程序一起存储的,对吗?
  • 实际上,在函数内部声明的静态变量至少在控制第一次到达它们时就被初始化了。例如,如果它是一个常量,则允许编译器在启动时进行初始化。
【解决方案3】:

您的问题似乎不是关于一般的静态变量,而是关于在函数内部声明的静态变量。

从运行时值初始化此类变量的额外运行时成本源于多个来源

  1. 当控件第一次越过其声明时(如果有的话),此类变量应仅初始化一次。为了实现为每个这样的变量分配一个额外的布尔变量/标志,并在每次控制通过声明时检查。如果标志表明该变量尚未初始化,则它会被初始化。

  2. 对于那些具有非平凡析构函数的静态变量,语言必须保证它们在程序终止时的销毁顺序与其构造顺序相反。由于构建顺序是在运行时确定的,因此程序必须准备一个运行时结构来安排未来的销毁。对于具有非平凡析构函数的变量,这也是步骤 1 的一部分:它们按照构造顺序注册在构造对象的“列表”中。 “列表”通常实现为预分配的数组(因为它的最大大小在编译时已知)。

  3. 在多线程配置中,上述步骤可能/将伴随着额外的锁定/解锁步骤。

由于这些都是“幕后”实施的“家庭”费用,实际成本可能在很大程度上取决于实施情况。查看/分析您的特定编译器生成的代码。

【讨论】:

    【解决方案4】:

    设置alternate1值意味着调用函数,即使函数返回一个静态值,你也必须保存堆栈,调用函数,获取它的返回值,恢复堆栈并将值分配给一个变量。

    从字面上看,在第一种情况下,您将执行至少 8 行汇编代码,而在第二种情况下 - 只执行一行。

    【讨论】:

    • 如果编译器可以在编译时知道它的值并优化它,则不需要调用另一个函数。此外,在没有讨论优化(包括 LTO)、CPU、CISC 与 RISC 等之间的区别的情况下,您可以量化每种情况需要多少“汇编代码行”的想法对我来说似乎很荒谬。这不是一个普遍的事情。
    猜你喜欢
    • 2019-04-23
    • 1970-01-01
    • 2010-09-26
    • 1970-01-01
    • 2011-08-22
    • 2010-12-22
    • 2020-12-09
    • 1970-01-01
    • 2017-05-13
    相关资源
    最近更新 更多