
Unity 中的垃圾是软件需要将数据存储在堆上,并且内存分配不再使用,所以完全无法避免,减少垃圾的较为有效方法是尽可能的避免产生垃圾。
一般情况下局部值类型变量,例如布尔值、数据结构、整数、双精度数和浮点数都存储在堆栈上,这是一种快速的临时数据,不会产生任何垃圾。
因此,当调用一个函数时,在其中声明和使用的任何本地值都将在堆栈上分配,并且不会产生任何垃圾。
void GarbageFunction()
{
int number = 2;
int otherNumber = 2;
int total = number + otherNumber;
}
一般情况下这种仅适用于在函数中本地声明临时变量时,而在类顶部声明的成员变量,例如,与类本身一起存储在堆上。
如果引用类型,类的新实例,那么它们的内存分配在堆上,而指向它们方位的指针存在于堆栈上。那么这就意味着简单地创建对已经存在的类的引用不会自行产生垃圾,由于对数据方位的堆栈引用仅仅链接到堆上现有的内存分配,它不会创建一个新的。
例如,多个新的堆栈引用都可以指向相同的堆数据分配,而不会产生任何垃圾。同样,如果堆栈指针实际上没有引用任何内容,例如因为它是空的,那么就不会为堆分配内存,也不会创建垃圾。
但是,当我们创建一个类的新实例时,该新内存将分配给堆。
public class GarbageCreator : MonoBehaviour
{
void GarbageFunction()
{
Number number = new Number(2);
Number otherNumber = new Number(2);
int total = number.value + otherNumber.value;
}
}
public class Number
{
public int value;
public Number(int newValue)
{
value = newValue;
}
}
尽管这是将两个数字相加的不走寻常路的一种办法,但它至少展现了一种创建少数垃圾的基本办法。在这种情况下,每个新的数字类都只是临时使用,这意味着一旦函数超出范围,就不再需要它们。
当这种情况发生时,它们的堆数据不再从堆栈中引用,从而使其成为垃圾。这不一定是个问题,特别是因为这个函数创建的垃圾量非常小,只有几十字节。
但是,如果频繁地向堆分配新的临时内存,例如在更新中的每一帧期间,即使是少量的垃圾也会很快累积并影响游戏性能。
一般情况下堆数据的任何临时分配都可能产生垃圾,但我门也可以通过查找会产生垃圾的进程来查看数据,通常较为好的方法是使用 Unity 中的 Profiler。