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

在C#(Unity)中使用静态临时变量有什么好处吗?,c#,unity3d,C#,Unity3d,我知道本地声明的变量会被编译成与StackOverflow答案基本相同的代码。但是,它不包括创建和使用静态对象,特别是Unity对象。我对C语言的知识来自C++,只是直接跳入统一,过去的实践看到我使用临时变量而不是很好地命名。我想在我的下一个项目中使用更好的实践,在这个项目中,可读性显然是有价值的,但性能更重要。所以考虑这两个代码…< /P> 与静态温度 public class Shot : MonoBehaviour { static Actor tempActor; sta

我知道本地声明的变量会被编译成与StackOverflow答案基本相同的代码。但是,它不包括创建和使用静态对象,特别是Unity对象。我对C语言的知识来自C++,只是直接跳入统一,过去的实践看到我使用临时变量而不是很好地命名。我想在我的下一个项目中使用更好的实践,在这个项目中,可读性显然是有价值的,但性能更重要。所以考虑这两个代码…< /P> 与静态温度

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();
            }
        }
    }
}
公共类快照:单行为{
静态演员-临时演员;
静态向量3-tempVec;
静态浮点数;
静态hit结果hit结果;
公众浮标损害;
公共交通畅通;
公共矢量3起始点;
专用无效对撞机(对撞机碰撞){
if(collision.gameObject.layer==11){
tempActor=collision.gameObject.GetComponent();
if(临时演员!=null){
tempVec=collision.transform.position-起始点;
//投射射线
Originator.RayDisableColliders();

bool rayHit=Physics.Raycast(originationPoint,tempVec,out-hitResult,range,1最大的问题不是性能,而是正确性。以这种方式使用静态字段会改变其含义,并可能导致以下任一方面的大问题:

  • 多个线程访问相同的静态值,并在进程中相互踩踏
    • 作为一种特殊情况,这不仅会导致意外值,还会导致“撕裂”值,因为您提到了过大的结构,如
      Vector3
  • 调用可重入性的任何内容;调用堆栈中的每个方法都将在不考虑任何预期行为的情况下践踏该值
基本上:除非你有很好的理由,不要这样做(也就是说,不要滥用临时局部变量的静态字段);而是使用常规局部变量


在性能方面有什么不同吗

速度方面,几乎可以肯定不是,但你必须用benchmarkdotnet之类的东西来衡量它

特别是在我看来,内存分配和垃圾收集


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

我倾向于同意Marc Gravel的主要概念,但我认为他的答案与C#相关,而不是与统一相关

是的。我同意c#wise将静态值与线程混合会产生问题

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

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

速度性能 参考类型

  • 引用值无论如何都会存在于堆中。就速度而言,最好将它们保持为静态,否则它们将继续从堆中分配/取消分配
值类型

  • 对于值类型,则是另一种情况。如果它们是静态的,则将它们永久(在几乎所有情况下)存储在堆上,而本地值类型将在堆栈中生存(相当短的寿命…)
  • 如果您将它们作为静态对象放在堆上,通常我希望您需要更多的时间来访问它们
  • 如果在堆栈中分配它们(作为本地值),速度会快得多
内存性能
  • 对于值类型,最好在堆栈中分配它们(如本地值)
  • 内存方面的引用类型应该更好地作为本地值。您可以根据需要将它们保留在内存中。正如Mark所解释的,对于静态字段,您可以无限期地将它们保留在内存中
值类型作为本地值肯定更好。引用类型作为静态值在速度上更具性能,但作为本地值在内存上更具性能

一般来说,在你的具体情况下,我看不到任何大的变化,即使是大量的电话

您仍然可以尝试使用进行基准测试(因为它不适用于开箱即用的unity)

在我这边


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

如果垃圾收集成为您真正的问题,我们应该很快(tm)使增量垃圾收集变得稳定。如果您使用的是Unity2019.2(我认为2019.1也有)你已经可以使用实验版本了,它基本上只是
项目设置-播放器-其他设置-配置
下的一个复选框,你需要勾选。如果你曾经实例化过多个
快照
对象,你就会看到这个意义上的静态问题。另外,没有什么可以阻止你在临时例子中,你并不是在做一个临时变量,你只是在做一个临时的引用。在垃圾回收方面,这完全不同。它相当于释放C++中的指针,实际上释放了一个不同的好建议。因为我是唯一的开发者,而我不使用多线程。这段代码,我并不担心。我知道我的任何临时变量只有在我自己立即填充时才被访问,所以我不会受到垃圾信息的影响。我只关心性能,就像我们使用对象池来减少Unity中的垃圾收集一样,我的错误想法是任何恒定内存分配都是无效的对性能和内存消耗都很好。我需要查找对象图,因为这个概念对我来说是陌生的!@DavidCoombes是的,这不是正确的想法;你实际上不是在这里谈论分配-在分配方面,没有什么不同
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();
            }
        }
    }
}