从Optimizing Software in C++ (Section 7.1),
静态数据的优点是可以将其初始化为所需的数据 程序启动前的值。缺点是内存 整个程序执行期间都会占用空间,即使 变量仅在程序的一小部分中使用。 这使数据 缓存效率较低。
在此static
的用法除了在静态存储持续时间的确切情况下适用于C和C ++之外,均如此。
谁能阐明为什么静态持续时间变量的数据缓存效率低(或是否低)?这是一个具体的比较:
void foo() {
static int static_arr[] = {/**/};
}
void bar() {
int local_arr[] = {/**/};
}
我看不出任何理由说明静态数据与其他任何类型的数据都不一样。在给定的示例中,我认为foo
会更快,因为执行堆栈不必加载static_arr
,而在bar
中,执行堆栈必须加载{{1 }}。在任何一种情况下,如果重复调用这些函数,则local_arr
和static_arr
都将被缓存。我错了吗?
答案 0 :(得分:6)
通常,Agner Fog通常知道他在说什么。
如果我们在 7.1种不同类型的变量存储部分的上下文中阅读引号,我们会在开始时看到他所说的“ 效率较低的缓存”部分:
如果数据随机分散在内存中,则数据缓存效果不佳。它是 因此了解变量的存储方式非常重要。存储原则是 对于简单的变量,数组和对象也是如此。
因此,说static
变量的缓存效率较低的想法是,存储变量的存储位置被“冷”(不再位于缓存中)的机会大于堆栈存储器的机会,具有自动存储期限的变量将存储在哪里。
考虑到缓存和分页,是数据存储的物理和时间局部性的组合会影响性能。
答案 1 :(得分:4)
该语句是否有意义取决于您的标点方式:
阅读1:
静态数据的优点是可以在程序启动之前将其初始化为所需的值。缺点是,即使变量仅在程序的一小部分中使用,整个程序执行仍会占用存储空间。
以上所有使数据缓存效率降低。
这是胡说八道。
阅读2:
静态数据的优点是可以在程序启动之前将其初始化为所需的值。
缺点是在整个程序执行过程中都会占用内存空间...
...即使该变量仅在程序的一小部分中使用。在某些情况下,这可能会使数据缓存效率降低。
在这种情况下,静态变量将被分配存储在一个页面中,该页面不总是被交换,或者位于一个很少使用的高速缓存行中。您可能会导致高速缓存未命中,或者从理论上讲,在最坏的情况下可能会导致页面错误(尽管坦白地说,这几天我们可以使用大量物理内存,如果发生这种情况,则可能会遇到更大的问题)。
在您演示的特定情况下,答案将是“取决于”。
是的,static_arr
的初始化是一次性的操作,因此可以认为是无成本的。
是的,local_arr
的初始化在每次调用函数时发生,但是可能是这样的:
通常,除非您有特定的优化想法,否则最好编写明确声明您想要的行为的代码,即:
当变量/数组的值在连续调用该函数后仍可继续使用时,请使用静态变量(具有静态存储持续时间的变量)。
当现有值在函数进入或退出时无意义时,请使用局部变量(严格来说是具有自动存储期限的变量)。
您会发现,在几乎所有情况下,编译器都会在优化通过后执行最高效的操作。
在特定情况下,静态初始化为Better(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;
}
答案 2 :(得分:3)
rustyx的回答对此进行了解释。局部变量存储在堆栈中。当函数返回时释放堆栈空间,并在调用下一个函数时重新使用堆栈空间。局部变量的缓存效率更高,因为相同的存储空间可以一次又一次地被重用,而静态变量则分散在不同的存储器地址中,而这些地址永远都不能再用于其他目的。静态数据是存储在DATA节中(初始化)还是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
...
}