做静态变量会阻碍数据缓存

Do Static Variables Impede Data Caching?

本文关键字:数据 缓存 静态 变量      更新时间:2023-10-16

来自在C 中优化软件(第7.1节),

静态数据的优点是可以将其初始化为所需 程序启动之前的值。缺点是记忆 在整个程序执行过程中,空间被占用,即使 变量仅在程序的一小部分中使用。这使数据 缓存效率较低。

static在此中的使用情况除外,因为它适用于静态存储持续时间的C和C 。

任何人都可以阐明为什么(或)数据缓存对于静态持续变量的效率较低吗?这是一个特定的比较:

void foo() {
  static int static_arr[] = {/**/};
}
void bar() {
  int local_arr[] = {/**/};
}

我看不出静态数据会与任何其他类型的数据不同的原因不同。在给定的示例中,我认为foo会更快,因为执行堆栈不必加载static_arr,而在bar中,执行堆栈必须加载local_arr。无论哪种情况,如果这些函数被重复调用,则static_arrlocal_arr均被缓存。我错了吗?

一般而言,Agner Fog通常知道他在说什么。

如果我们在 7.1节的上下文中阅读了报价,不同种类的可变存储,我们在开始时看到了他的含义"部分:

数据缓存如果数据在存储器中随机散布,则数据缓存很差。这是 因此,重要的是了解变量如何存储。存储原理是 对于简单的变量,数组和对象也一样。

因此,说static变量的想法较少,高速缓存效率低的是,存储存储的存储位置的机会是"冷"(不再在高速缓存中)比堆栈内存更大,这就是变量的位置随着自动存储持续时间将存储。

考虑到缓存和分页,正是数据存储的物理和时间局部性的组合影响了性能。

Rustyx的答案解释了它。局部变量存储在堆栈上。当功能返回并重复使用下一个功能时,堆栈空间将发布。缓存对于局部变量更有效,因为相同的内存空间一次又一次地重复使用,而静态变量则散布在不同的内存地址上,而这些记忆地址永远无法为其他目的重复使用。静态数据是否存储在数据部分(初始化)或BSS部分(未经知识化)中,这在这方面没有任何区别。堆栈最高空间可能会在整个程序执行过程中保持缓存,并多次重复使用。

另一个优点是,相对于堆栈指针,可以使用8位偏移访问有限数量的本地变量,而静态变量需要32位绝对地址(以32位x86)或32位相对地址(x86-64)。换句话说,本地变量可能会使代码更加紧凑,并改善代码缓存以及数据缓存。

// Example
int main () {
  f();
  g();
  return 0;
}
void f() {
   int x; 
   ...
}
void g() {
   int y;  // y may occupy the same memory address as x
   ...
}

该语句确实有意义,具体取决于您的打点:

阅读1:

静态数据的优点是可以在程序启动之前将其初始化为所需的值。缺点是,即使变量仅在程序的一小部分中使用,内存空间都会在整个程序执行中占据。

以上所有这些使数据缓存效率降低。

这是胡说八道。

阅读2:

静态数据的优点是可以在程序启动之前将其初始化为所需的值。

缺点是在整个程序执行中占据内存空间...

...即使变量仅在程序的一小部分中使用。在某种情况下,这可以使数据缓存效率降低。

这种情况将是在不总是交换的页面中分配静态变量的地方,或者在很少使用的缓存线上。您可能会导致缓存失误,或者在最坏的情况下,在理论上是一个故障(坦率地说,如今,有大量的物理记忆,如果发生这种情况,您有更大的问题)。

在您证明的具体情况下,答案是"取决于"。

是的, static_arr的初始化是一次性的一次操作,因此可以被认为是无偿的。

是的,每次调用函数时,local_arr的初始化都会发生,但可能是:

  1. 此初始化是微不足道的,
  2. 作为优化器Pass的一部分,编译器将初始化含量

通常,除非您有特定的优化,否则(TM)最好编写明确指示您想要的行为的代码,即:

  • 使用静态变量(带有静态存储持续时间的变量)时,当变量/数组的值应连续呼叫到该功能。

  • 当现有值在输入或从函数中退出时毫无意义时,请使用本地变量(严格,具有自动存储持续时间的变量)。

您会发现编译器在几乎所有情况下都将在优化通过后做最有效的事情。

在某种情况下,静态初始化更好(TM)。如果是(说)需要动态分配的缓冲区。您可能不想在每个呼叫上产生分配/交易成本。您可能希望缓冲区在需要时动态增长,并根据未来的操作可能再次需要记忆。

在这种情况下,变量的实际状态是其分配的缓冲区的大小。因此,状态对于函数的输入和退出很重要,例如:

  std::string const& to_string(json const& json_object)
  {
    static thread_local buffer;               // thread-safe, auto-expanding buffer storage
    buffer.clear();                           // does not release memory
    serialise_to_string(buffer, json_object); // may allocate memory occasionally
    return buffer;
  }