为了账号安全,请及时绑定邮箱和手机立即绑定

在 C# (Unity) 中使用静态临时变量有什么好处吗?

在 C# (Unity) 中使用静态临时变量有什么好处吗?

C#
一只名叫tom的猫 2023-08-20 14:38:18
我想在我的下一个项目中使用更好的实践,其中可读性显然很有价值,但性能更重要。所以考虑这两段代码......在静态温度...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;两种方法之间在性能方面有什么区别,特别是在我看来内存分配和垃圾收集?
查看完整描述

2 回答

?
喵喵时光机

TA贡献1846条经验 获得超7个赞

最大的问题不是性能 - 而是正确性。以这种方式使用静态字段会改变含义,并可能导致以下任一方面的大问题:

  • 多个线程访问相同的静态值并在进程中互相踩踏

    • 作为一种特殊情况,这不仅可能导致意外的值,而且还可能导致“撕裂”值,因为您提到了过大的结构,例如Vector3

  • 任何需要重入的东西;调用堆栈中的每个方法都会忽略该值,而不考虑任何预期的行为

基本上:除非你有很好的理由,否则不要这样做(即不要滥用临时本地变量的静态字段);请改用常规局部变量。


性能上有什么区别吗

就速度而言,几乎肯定不是,但你必须使用 benchmarkdotnet 之类的东西来衡量它

在我看来,尤其是内存分配和垃圾收集

通过将值放入静态字段,您可以通过该值使任何对象可达:可达。如果您从不清除该字段,它可能会不必要地使任意大的对象图保持活动状态。


查看完整回答
反对 回复 2023-08-20
?
Smart猫小萌

TA贡献1911条经验 获得超7个赞

我倾向于同意 Marc Gravell 的主要概念,但我认为他的答案更多地与 C# 相关,而不是与 Unity 相关。

是的。我同意 C# 明智地将静态值与线程混合可能会产生问题......

但在您的特定情况下,OnTriggerEnter可以仅在主线程上运行(例如许多其他与统一相关的方法),因此您没有这样的风险(除非您开始在方法之外使用这些字段OnTriggerEnter)。

无论如何,情况是这样的:

速度性能

参考文献类型

  • 无论如何,参考值都会存在于堆中。从速度方面来说,最好将它们保持静态,否则它们将继续从堆中分配/取消分配。

价值类型

  • 对于值类型则是另一回事了。如果它们是静态的,您将把它们永久存储在堆上(几乎在所有情况下),而本地值类型将存在于堆栈中(寿命相当短......)

  • 如果您将它们作为静态放在堆上,我预计,一般来说,您将需要更多时间来访问它们

  • 如果将它们分配在堆栈中(作为本地值),速度会快得多

内存性能

  • 对于值类型,最好将它们分配在堆栈中(以及本地值)。

  • 内存方面,引用类型也应该比本地值更好。您可以根据需要将它们保留在内存中。正如马克所解释的,使用静态字段,您可以将它们无限期地保留在内存中。

值类型肯定比本地值更好。引用类型在速度方面比静态的性能更高,但在内存方面比本地的性能更高。

一般来说,在您的具体情况下,即使是大量呼叫,我也没有看到任何大的变化。

您仍然可以尝试使用Unity 基准测试工具对其进行基准测试(因为BenchmarkDotNet不适用于开箱即用的 Unity)。

就我而言...

我会使用本地值,更具可读性。


查看完整回答
反对 回复 2023-08-20
  • 2 回答
  • 0 关注
  • 121 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信