在游戏中,计算渲染最后一帧(增量时间)以产生平滑移动,定时器等所花费的时间非常常见。
这样做的一种方法是声明3个全局变量:
float deltaTime, currentTime, elapsedTime;
然后计算游戏循环开始时的增量时间:
currentTime = getTime();
deltaTime = currentTime - elapsedTime;
elapsedTime = currentTime;
(其中getTime()是一个返回自程序启动以来的时间的函数)
另一种方法是将 deltaTime 和 currentTime 声明为局部变量:
float currentTime = glfwGetTime();
float deltaTime = currentTime - elapsedTime;
elapsedTime = currentTime;
如果我的理解是正确的,那么编译器必须在循环结束时释放变量的内存,并且在循环的下一次迭代中,再次重新分配它,导致它比仅仅声明更低效全局变量。
这是正确的还是在后台自动发生的其他一些我不知道的事情?
答案 0 :(得分:7)
如果我的理解是正确的,那么编译器必须在循环结束时释放变量的内存,并且在循环的下一次迭代中,再次重新分配它,导致它比仅仅声明更低效全局变量。
那不是真的。
编译器不在循环中为局部变量分配和释放内存。通常,在创建函数的堆栈帧时分配函数中局部变量的内存。
变量在循环的每次运行中初始化。
如果变量是一个具有构造函数和析构函数的类类型,它们将在循环的每次运行中被调用,这可能是昂贵的,这取决于构造函数和析构函数中发生的事情,循环的次数是运行
对于float
类型,由于在循环中使用局部变量,不应该有任何开销。如果有的话,我会非常惊讶。
答案 1 :(得分:1)
源代码:
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
一次内存写
一次内存提取:
vsubss xmm0, xmm0, DWORD PTR elapsedTime[rip]
两次内存写入,其中一次是冗余的。
vmovss DWORD PTR elapsedTime[rip], xmm1
vmovss DWORD PTR deltaTime[rip], xmm0
在全局中存储deltaTime的总开销是一次内存写入。没有什么比表现更好的,但肯定是不受欢迎的风格。
避免全局变量的原因与性能无关,它与避免紧耦合有关。