堆栈(本地)还是全局变量?

时间:2012-01-13 22:58:02

标签: c++ c

使用全局变量会加快速度吗? 在英特尔架构软件开发人员手册(关于微处理器)中,建议使用局部变量而不是全局变量。但是,请考虑以下代码:

void process_tcp_packets(void) {
    char tcp_data[128];

    do some stuff with the tcp_data[]....
}

void process_udp_packets(void) {
    char udp_data[128];

    do some stuff with the udp_data[]
}
void main_event_loop(void) {

    while(1) {
         if (pending_tcp_requests) {
             process_tcp_packets();
         }
         if (pending_udp_requests) {
             process_udp_packets();
         }
   }
}

当执行main_event_loop()时,流的控制取决于变量“pending_tcp_requests”和“pending_udp_requests”。调用时,process_tcp_packets()和process_udp_packets()函数都将在当前堆栈指针处分配局部变量。这意味着如果代码不断切换两个函数,则局部变量将分配在相同的内存地址中。在两个函数之间共享内存地址将从当前L1缓存中逐出数据并且执行缓慢。 因此,通过使用全局变量而不是本地变量,我们可以加快执行速度。 它是否正确?

如果是这样,在这种情况下使用全局变量有什么缺点吗?

5 个答案:

答案 0 :(得分:4)

  

在两个函数之间共享内存地址将从当前L1缓存中逐出数据并减慢执行速度。因此,通过使用全局变量而不是本地变量,我们可以加快执行速度。它是否正确?

对于单线程使用内存,你的前提是不正确的。

使用不同的CPU缓存在线程之间共享相同的内存将导致缓存争用(通常是刷新)。使用相同的CPU缓存在同一线程上的函数之间共享内存根本不会这样做。

此外,在某些平台上,局部变量比全局变量需要更少的访问指令(因为它们是堆栈指针本地的偏移,并且通常可以以< = 2字节编码,其中全局变量可能不是)。

答案 1 :(得分:4)

在这种情况下,全局变量不太可能给你带来好处。

  1. 堆栈中的“分配”内存只是向堆栈指针添加一个数字,即一个半周期操作。
  2. 在64kb时,L1缓存足够大,可以包含许多堆栈帧。此外,最近几个堆栈帧(因为你在调用函数时推入params)几乎总是在缓存中。实际上,要分配的 next 帧的区域通常在L1中,因为您经常只退出使用它的其他函数。
  3. 相比之下,全局变量很快就会脱离L1。请记住,在每个函数的开头和结尾都会触及堆栈(只是为了推送返回地址),而process_tcp_packets()和process_udp_packets()都将使用大致相同的地址空间来存储它们的本地。
  4. 在函数之间共享内存地址不会从缓存中逐出数据。相反,它会让你更多可能会遇到缓存。 The more recently you have touched an address, the more likely it is to be in cache

答案 2 :(得分:1)

最好的办法是衡量。但请注意,数组在语义上总是新的,尽管它们最终会保留前面的字节。如果你真的打算在这些数组中保留一些状态,你需要使它们static,在这种情况下它们也会得到不同的内存区域。我没有测量,但我希望使用局部变量比全局变量更快,因为除非缓存溢出,否则永远不需要将它们实际写入内存。

答案 3 :(得分:1)

您可以修复您描述的问题,而无需使用全局变量。在上面的堆栈中创建一个局部变量,并将引用(指针)传递给该方法。这是两全其美的。

void process_tcp_packets(char** tcp_data) {
    do some stuff with the tcp_data[]....
}

void process_udp_packets(char** udp_data) {
    do some stuff with the udp_data[]
}

void main_event_loop(void) {
    char udp_data[128];
    char tcp_data[128];
    while(1) {
         if (pending_tcp_requests) {
             process_tcp_packets(&tcp_data);
         }
         if (pending_udp_requests) {
             process_udp_packets(&udp_data);
         }
   }
}

出于多种原因,应避免使用全局变量。最终,由于太多可能访问全局的地方(即整个程序),很难知道数据在全局变化的原因。通过使用局部变量,除非明确传递,否则无法从执行块外部访问变量。这允许将程序划分为几种可以访问特定内存的方法,极大地简化了调试和维护程序的能力(随着时间的推移)。

答案 4 :(得分:0)

对于你所建议的内容的一个中间道路是在函数中将这些数组变量声明为static。它们“充当”全局变量,因为对函数的所有调用都重用了数组的相同内存位置,但是没有全局变量的范围问题 - 数组只能 才能访问他们各自的职能。

void process_tcp_packets(void) {
    static char tcp_data[128];

    do some stuff with the tcp_data[]....
}

void process_udp_packets(void) {
    static char udp_data[128];

    do some stuff with the udp_data[]
}