You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity C#:静态临时变量与局部临时变量的性能差异对比

静态临时变量 vs 局部临时变量:Unity中的性能与GC对比

先看你给出的两段代码对比:

使用静态临时变量的代码

public class Shot : MonoBehaviour {
 static Actor tempActor;
 static Vector3 tempVec;
 static float tempFloat;
 static HitResult hitResult;
 public float damage;
 public float unblockable;
 public Vector3 originationPoint;
 private void OnTriggerEnter(Collider collision) {
 if (collision.gameObject.layer == 11) {
 tempActor = collision.gameObject.GetComponent<Actor>();
 if (tempActor != null) {
 tempVec = collision.transform.position - originationPoint;
 // cast ray
 originatorActor.RayDisableColliders();
 bool rayHit = Physics.Raycast(originationPoint, tempVec, out hitResult, range, 1<<11, QueryTriggerInteraction.Ignore);
 if (rayHit) {
 if (hitResult.collider.gameObject.CompareTag("Hero") || hitResult.collider.gameObject.CompareTag("Villain")) {
 tempActor = hitResult.collider.gameObject.GetComponent<Actor>();
 tempActor.HitByShot(class_utilities.GetAngle(hitResult.transform, originationPoint), damage, unblockable);
 }
 }
 originatorActor.RayEnableColliders();
 }
 }
 }
}

使用局部临时变量的代码

public class Shot : MonoBehaviour {
 public float damage;
 public float unblockable;
 public Vector3 originationPoint;
 private void OnTriggerEnter(Collider collision) {
 if (collision.gameObject.layer == 11) {
 Actor tempActor = collision.gameObject.GetComponent<Actor>();
 if (tempActor != null) {
 Vector3 offset = collision.transform.position - originationPoint;
 // cast ray
 originatorActor.RayDisableColliders();
 HitResult hitResult;
 bool rayHit = Physics.Raycast(originationPoint, offset, out hitResult, range, 1<<11, QueryTriggerInteraction.Ignore);
 if (rayHit) {
 if (hitResult.collider.gameObject.CompareTag("Hero") || hitResult.collider.gameObject.CompareTag("Villain")) {
 tempActor = hitResult.collider.gameObject.GetComponent<Actor>();
 tempActor.HitByShot(class_utilities.GetAngle(hitResult.transform, originationPoint), damage, unblockable);
 }
 }
 originatorActor.RayEnableColliders();
 }
 }
 }
}

接下来咱们直接聊核心的性能(内存分配+GC)差异,还有你需要注意的坑:

一、内存分配与GC:几乎无差异,但有本质区别

  • 局部变量版本:

    • 像Vector3 offset、HitResult hitResult这类值类型,会直接分配在栈内存上,方法执行完毕后栈帧自动销毁,完全不会触发GC,也没有堆分配开销。
    • 引用类型变量Actor tempActor只是栈上的一个指针,你这里是通过GetComponent获取已存在的对象,没有新实例化任何对象,所以也不会产生堆内存分配。
    • 哪怕是out参数的HitResult,因为是结构体(值类型),传递的是栈上的副本,同样没有GC压力。
  • 静态变量版本:

    • 静态变量存储在堆的静态存储区,从程序启动到退出一直存在,不会被GC回收(除非手动置空且无其他引用,但这里是类的静态成员,会一直存活)。
    • 每次使用只是覆盖静态变量的值,同样不会产生新的内存分配,也不会触发GC。
    • 但这里有个致命的隐患:多实例冲突!如果有多个Shot实例同时触发OnTriggerEnter(比如一堆子弹同时命中目标),静态变量会被互相覆盖——比如第一个子弹刚赋值tempActor,还没执行完逻辑,第二个子弹就把tempActor改成自己的目标,直接导致逻辑错误,这可比性能问题严重多了。另外,静态变量会一直占用内存,哪怕所有Shot都被销毁,这些变量还留在内存里,虽然单个占比小,但积少成多也会有影响。

二、CPU性能:几乎可以忽略的差异

两种写法在CPU开销上没有明显区别:不管是栈上分配局部变量,还是覆盖静态变量,都是极轻量的操作,现代CPU完全能处理,不会成为性能瓶颈。

三、可读性与维护性:局部变量版本完胜

你提到可读性重要但性能优先,但其实局部变量版本的可读性反而更好——比如把模糊的tempVec改成offset,变量名直接体现用途;而且局部变量的作用域只在方法内,不会污染类的其他区域,也不会有跨实例的干扰问题,后续维护起来更省心。

最终建议

如果只看内存分配和GC,两种写法几乎没有差异,但静态变量版本存在多实例冲突、内存长期占用的隐患,反而局部变量版本更安全、可读性更好,性能上也没损失。所以完全没必要用静态临时变量,直接采用局部变量的写法就好。

内容的提问来源于stack exchange,提问作者David Coombes

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 06:51:47