全局变量和局部变量哪个更有效?

Are global or local variables more efficient?

本文关键字:有效 局部变量 全局变量      更新时间:2023-10-16

在游戏中计算渲染最后一帧所需的时间(delta time)是很常见的,以便产生平滑的运动、计时器等。

一种方法是声明3个全局变量:
float deltaTime, currentTime, elapsedTime;

然后计算游戏循环开始时的增量时间:

currentTime = getTime();
deltaTime = currentTime - elapsedTime;
elapsedTime = currentTime;

(其中getTime()是返回程序启动后的时间的函数)

另一种方法是将deltaTimecurrentTime声明为局部变量:
float currentTime = glfwGetTime();
float deltaTime = currentTime - elapsedTime;
elapsedTime = currentTime;

如果我的理解是正确的,那么编译器必须在循环结束时重新分配变量的内存,并且在循环的下一次迭代中再次重新分配它,导致它比仅仅声明全局变量更低效。

这是正确的,还是有一些其他的东西自动发生在后台,我不知道?

如果我的理解是正确的,那么编译器必须在循环结束时重新分配变量的内存,并且在循环的下一次迭代中再次重新分配它,导致它比仅仅声明全局变量更低效。

那不是真的。

编译器不会为循环中的局部变量分配和释放内存。函数中局部变量的内存通常在创建函数的堆栈帧时分配。

变量在每次循环运行时初始化。

如果变量是具有构造函数和析构函数的类类型,则它们将在每次循环运行时被调用,这可能是昂贵的,这取决于构造函数和析构函数中发生的事情,以及循环运行的次数。

对于float类型,不应该因为在循环中使用局部变量而产生任何开销。

源代码:
extern float getTime();
float deltaTime, currentTime = getTime(), elapsedTime = getTime();
float time_it()
{
  currentTime = getTime();
  deltaTime = currentTime - elapsedTime;
  elapsedTime = currentTime;
  return deltaTime;
}

对象代码:

time_it():
        sub     rsp, 8
        call    getTime()
        vmovss  DWORD PTR currentTime[rip], xmm0
        vmovaps xmm1, xmm0
        vsubss  xmm0, xmm0, DWORD PTR elapsedTime[rip]
        vmovss  DWORD PTR elapsedTime[rip], xmm1
        vmovss  DWORD PTR deltaTime[rip], xmm0
        add     rsp, 8
        ret

重要的是什么?

call getTime() -迄今为止所有系统上最昂贵的操作

vmovss DWORD PTR currentTime[rip], xmm0 one memory write

一次内存获取:vsubss xmm0, xmm0, DWORD PTR elapsedTime[rip]

两个内存写入,其中一个是冗余的。

vmovss DWORD PTR elapsedTime[rip], xmm1vmovss DWORD PTR deltaTime[rip], xmm0

在全局变量中存储deltaTime的总开销是一次内存写入。性能方面没有什么值得兴奋的,但风格方面肯定不受欢迎。

避免全局变量的原因与性能无关,而是与避免紧耦合有关。