回收价值类型统一有什么意义吗
is there a point in recycling value types unity
我发现文章指出回收和重用变量是统一的好做法。所以我采用了它。
但有一件事不清楚:这是否适用于值类型变量(整数、向量)?
我使用这个有什么意义吗:
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
}
这完全取决于您希望对此对象执行的操作。
让我们举第一个例子,假设我们想从第二个函数访问变量 x 和 v functionCalledEveryOnceSoOften()
这个函数不需要任何重载来传递变量,并且可以直接访问class.
实例中的变量
对于第二个例子,如果我们想做同样的事情。我们必须调用 functionCalledEveryOnceSoOften(int, vector3)
因为该函数不能直接访问变量。
在 unity 中,一个函数通常需要使用与另一个函数相同的值,尽管它们可能并不总是在链中调用。为了在你的第二个例子中适应这一点,我们必须在我们的函数中添加 if
语句来过滤掉它。
然而,在您的第一个示例中,我们可以毫无问题地使用这些变量。这是经常建议这样做的原因之一。
根据性能,在您的第二个示例中,变量存储在堆栈中而不是堆中,因为它是在方法的范围内定义的,一旦方法结束执行,该方法就会被销毁。所以变量的内存使用量并不是真正的问题。重复创建和销毁可能会有一点开销,但这应该是微不足道的。
在您的第一个示例中,您将变量存储在堆上,因为它是在 class 范围内定义的,它只会与 class 一起被销毁,并在这是实例化。这意味着内存可能会被使用更长的时间,但是 creating/destroying 变量不会有开销。这通常也是微不足道的。
总而言之,除非您正在实例化数千个这些对象,否则您很可能不会注意到快速连续访问变量的性能差异。
最大的区别很可能是代码的编写方式。不论结果好坏。
Is there a point in recycling value types unity
是的,有些数据类型不是全部。
does this apply to value type variables (integers, vectors)?
没有.
这取决于变量类型。
这 不适用于 int
、double
、float
、bool
、Vector3
和Vector2
和其他类似的数据类型。它甚至不适用于 string
,因为 string
已经不能在 C# 中重复使用。 strings
是不可变的。
事实上,在 while
循环中使用局部变量中的 int
比使用声明为全局变量的 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);
}
}
创建新对象:
创建新对象会占用资源并可能导致移动设备出现问题。这取决于您执行此操作的频率。
下面的代码创建了一个游戏对象(子弹),然后将 Rigidbody
附加到它上面,然后在按住 space 条的同时每帧射击 it.This,最后销毁子弹 10
秒后。
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);
}
}
上面的代码不好,因为它在每次创建新游戏对象时分配内存,当游戏对象被销毁时,它也会触发垃圾收集器。这可能会减慢速度并导致游戏出现问题。
上述代码的解决方案是对象池化。您可以在这里了解更多信息: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;
}
}
}
所以基本上,您在游戏开始之前在函数内创建一个对象,然后将引用存储在 全局 变量中。然后您将重新使用您在函数中创建的对象,因为它的引用保存在 global 变量中。
实例化:
Instantiate函数用于创建预制件的副本。
下面的代码将实例化一颗子弹,然后在按住 space 条的同时每帧射击它,并在 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);
}
}
上面的代码很糟糕,因为它根据附加到子弹预制件的组件数量以及它下面有多少子游戏对象来分配内存。解决方案也是使用 Object Pooling。在函数中实例化 GameObject,将引用存储在 global 变量中,然后重新使用它们。解决方法同上。
总之,您问题中的示例代码不适用此。
您可以了解有关 Unity 中内存管理的更多信息 here。
我发现文章指出回收和重用变量是统一的好做法。所以我采用了它。 但有一件事不清楚:这是否适用于值类型变量(整数、向量)?
我使用这个有什么意义吗:
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
}
这完全取决于您希望对此对象执行的操作。
让我们举第一个例子,假设我们想从第二个函数访问变量 x 和 v functionCalledEveryOnceSoOften()
这个函数不需要任何重载来传递变量,并且可以直接访问class.
对于第二个例子,如果我们想做同样的事情。我们必须调用 functionCalledEveryOnceSoOften(int, vector3)
因为该函数不能直接访问变量。
在 unity 中,一个函数通常需要使用与另一个函数相同的值,尽管它们可能并不总是在链中调用。为了在你的第二个例子中适应这一点,我们必须在我们的函数中添加 if
语句来过滤掉它。
然而,在您的第一个示例中,我们可以毫无问题地使用这些变量。这是经常建议这样做的原因之一。
根据性能,在您的第二个示例中,变量存储在堆栈中而不是堆中,因为它是在方法的范围内定义的,一旦方法结束执行,该方法就会被销毁。所以变量的内存使用量并不是真正的问题。重复创建和销毁可能会有一点开销,但这应该是微不足道的。
在您的第一个示例中,您将变量存储在堆上,因为它是在 class 范围内定义的,它只会与 class 一起被销毁,并在这是实例化。这意味着内存可能会被使用更长的时间,但是 creating/destroying 变量不会有开销。这通常也是微不足道的。
总而言之,除非您正在实例化数千个这些对象,否则您很可能不会注意到快速连续访问变量的性能差异。
最大的区别很可能是代码的编写方式。不论结果好坏。
Is there a point in recycling value types unity
是的,有些数据类型不是全部。
does this apply to value type variables (integers, vectors)?
没有.
这取决于变量类型。
这 不适用于 int
、double
、float
、bool
、Vector3
和Vector2
和其他类似的数据类型。它甚至不适用于 string
,因为 string
已经不能在 C# 中重复使用。 strings
是不可变的。
事实上,在 while
循环中使用局部变量中的 int
比使用声明为全局变量的 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);
}
}
创建新对象:
创建新对象会占用资源并可能导致移动设备出现问题。这取决于您执行此操作的频率。
下面的代码创建了一个游戏对象(子弹),然后将 Rigidbody
附加到它上面,然后在按住 space 条的同时每帧射击 it.This,最后销毁子弹 10
秒后。
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);
}
}
上面的代码不好,因为它在每次创建新游戏对象时分配内存,当游戏对象被销毁时,它也会触发垃圾收集器。这可能会减慢速度并导致游戏出现问题。
上述代码的解决方案是对象池化。您可以在这里了解更多信息: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;
}
}
}
所以基本上,您在游戏开始之前在函数内创建一个对象,然后将引用存储在 全局 变量中。然后您将重新使用您在函数中创建的对象,因为它的引用保存在 global 变量中。
实例化:
Instantiate函数用于创建预制件的副本。
下面的代码将实例化一颗子弹,然后在按住 space 条的同时每帧射击它,并在 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);
}
}
上面的代码很糟糕,因为它根据附加到子弹预制件的组件数量以及它下面有多少子游戏对象来分配内存。解决方案也是使用 Object Pooling。在函数中实例化 GameObject,将引用存储在 global 变量中,然后重新使用它们。解决方法同上。
总之,您问题中的示例代码不适用此。
您可以了解有关 Unity 中内存管理的更多信息 here。