我发现文章指出回收和重复使用变量是团结的良好做法。所以我采纳了它。 但有一点不清楚:这是否适用于值类型变量(整数,向量)?
有一点我使用它:
int x;
Vector3 v;
void functionCalledVeryOften(){
x=SomeCalculation();
v=SomeCalc();
//do something with x and v
}
而不是:
void functionCalledVeryOften(){
int x=SomeCalculation();
Vector3 v=SomeCalc();
//do something with x and v
}
答案 0 :(得分:5)
回收价值类型统一是否有意义
是的,有些数据类型不是全部。
这适用于值类型变量(整数,向量)吗?
否强>
这取决于变量类型。
不适用于int
,double
,float
,bool
,Vector3
和Vector2
和其他类似的数据类型。它甚至不适用于string
因为已经,string
无法在C#中重复使用。 strings
是不可变的。
事实上,使用本地变量中的int
,假设在while
循环中比使用声明为全局的int
更快。
*何时应该声明变量一次并重复使用它或用您自己的话说,在Unity *中回收或重复使用变量的示例。
<强>阵列强>:
如果函数包含数组,并且通常会调用该函数。
void functionCalledVeryOften()
{
float[] playerLives = new float[5]; //This is bad because it allocates memory each time it is called
for (int i = 0; i < playerLives.Length; i++)
{
playerLives[i] = UnityEngine.Random.Range(0f,5f);
}
}
每次分配内存,可以通过使数组全局并在函数外部初始化一次来解决。您可以创建一个简单的函数,将数组中的数据重置为0。
float[] playerLives = new float[5];
void functionCalledVeryOften()
{
for (int i = 0; i < playerLives.Length; i++)
{
playerLives[i] = UnityEngine.Random.Range(0f,5f);
}
}
创建新对象:
创建新对象会占用资源,并可能导致移动设备出现问题。这取决于你这样做的频率。
下面的代码创建了一个GameObject(项目符号),然后将Rigidbody
附加到它上面然后进行拍摄。这种情况发生在每一帧,同时按住空格键,最后在10
秒后摧毁子弹。 / p>
void functionCalledVeryOften()
{
if (Input.GetKey(KeyCode.Space))
{
//Create new Bullet each time
GameObject myObject = new GameObject("bullet");
Rigidbody bullet = myObject.AddComponent<Rigidbody>() as Rigidbody;
//Shoot Bullet
bullet.velocity = transform.forward * 50;
Destroy(myObject);
}
}
上面的代码很糟糕,因为每次创建新的GameObject时都会分配内存,当GameObject被销毁时,它也会触发垃圾收集器。这可能会减慢并导致游戏中的打嗝。
上述代码的解决方案是对象池。您可以在此处了解详情:Object Pooling tutorial from Unity
使用全局变量进行简单修复的示例:
List<GameObject> reUsableBullets;
int toUseIndex = 0;
void Start()
{
intitOnce();
}
//Call this function once to create bullets
void intitOnce()
{
reUsableBullets = new List<GameObject>();
//Create 20 bullets then store the reference to a global variable for re-usal
for (int i = 0; i < 20; i++)
{
reUsableBullets[i] = new GameObject("bullet");
reUsableBullets[i].AddComponent<Rigidbody>();
reUsableBullets[i].SetActive(false);
}
}
void functionCalledVeryOften()
{
if (Input.GetKey(KeyCode.Space))
{
//Re-use old bullet
reUsableBullets[toUseIndex].SetActive(true);
Rigidbody tempRgb = reUsableBullets[toUseIndex].GetComponent<Rigidbody>();
tempRgb.velocity = transform.forward * 50;
toUseIndex++;
//reset counter
if (toUseIndex == reUsableBullets.Count - 1)
{
toUseIndex = 0;
}
}
}
所以基本上,你在游戏开始之前在函数内创建一个Object,然后将引用存储在 global 变量中。然后,您将重新使用您在函数中创建的对象,因为它的引用保存在全局变量中。
<强>实例化强>:
Instantiate功能用于创建预制件的副本。
下面的代码将实例化一颗子弹,然后每按一次射击它,同时按住空格键,最后在10
秒后将其销毁。
public GameObject bulletPrefab;
void functionCalledVeryOften()
{
if (Input.GetKey(KeyCode.Space))
{
//Create new Bullet each time
Rigidbody bullet = Instantiate(bulletPrefab, new Vector3(0, 0, 0), Quaternion.identity) as Rigidbody;
//Shoot Bullet
bullet.velocity = transform.forward * 50;
Destroy(myObject,10f);
}
}
上面的代码很糟糕,因为它根据子弹预制件附加的组件数量以及游戏对象下面的子游戏数量来分配内存。该解决方案还使用对象池。在函数中实例化GameObject,将引用存储在 global 变量中,然后重新使用它们。解决方案与上述解决方案相同。
总之,您问题中的示例代码不适用于此。
您可以在Unity here中了解有关内存管理的更多信息。
答案 1 :(得分:2)
这完全取决于您希望如何处理此对象。
让我们举一个例子,说我们想要访问变量x&amp; v来自第二个函数functionCalledEveryOnceSoOften()
这个函数不需要任何重载来传递变量,并且可以直接访问类实例中的变量。
使用第二个例子,如果我们想做同样的事情。我们必须调用functionCalledEveryOnceSoOften(int, vector3)
因为函数不能直接访问变量。
在统一中,通常情况是函数需要使用与另一个函数相同的值,尽管它们可能并不总是在链中被调用。为了适应你的第二个例子,我们必须在我们的函数中添加if
语句来过滤它。
然而,在您的第一个示例中,我们可以使用这些变量而不会出现问题。这是通常建议这样做的原因之一。
根据性能,在第二个示例中,变量存储在堆栈中而不是堆中,因为它是在方法的范围内定义的,一旦方法结束执行,它将被销毁。因此,变量的内存使用并不是真正的问题。重复创建和销毁的开销可能很小,但这应该是微不足道的。
在第一个示例中,您将变量存储在堆上,因为它是在类的范围内定义的,它只会与类一起销毁,并在其实例上创建。这意味着内存可能会在更长的时间内使用,但创建/销毁变量不会产生任何开销。这通常也是微不足道的。
总之,除非您实例化数千个这些对象,否则快速连续访问变量,您很可能不会注意到性能上的很多差异。
最大的区别很可能是编写代码的方式。不论结果好坏。