移动设备没有独立显存(显存的作用是用来存储显卡芯片处理过或者即将提取的渲染数据),所有在移动端数据内存和显存是同一块内存。所以有可能我们游戏占用的内存并不大,但是依旧爆内存了,其实是因为显存分配不出来了。这种情况,我们可以去查看一下Log,例如Android会有一个 OpenGL Error:Out Of Memory。
假设我们有一个控制敌人的组件,名叫Enemy,代码如下:
public class Enemy : MonoBehaviour
{
public float maxSpeed;
public float attackRadius;
}这个组件挂载在每个敌人身上,但是其中这两个浮点数(maxSpeed 和 attachRadius)的数值都是不变的。那么当场景中存在很多的敌人时,每次生成敌人的时候,这些数据就会重复一份。
所以即使所有数据都一样,这两个浮点数还是重复的出现在有此脚本的对象上。所以建议改用Scriptable Objects,这样就只会耗费一组这样数据的内存,代码如下:
public class EnemyConfiguration : ScriptableObject
{
public float maxSpeed;
public float attackRadius;
}
public class Enemy : MonoBehaviour
{
public EnemyConfiguration enemyConfiguration;
}变量or属性
通常我们为了封装安全性,开发时会选择使用属性(getter/setter),而属性本质上是函数的调用,前面提到调用函数时,会在堆栈上分配内存,因此调用属性也是如此。当调用多次时,花费在堆栈中的时间就会增加。当然了,一般来说问题不大,但是如果在使用频繁的循环体中使用属性,可能就需要针对性的优化。
我们可以通过宏命令进行处理,例如在开发时使用属性,发布版本时使用变量,如下:
#if DELELOPMENT_BUILD
int m_health;
public int health { get => m_health; }
#else
public int health;
#endif缓存一些Hash值
在我们想要在运行时修改动画或者材质的时候,可以使用下面方法来实现
animator.SetTrigger("Idle");
material.SetColor("Color", Color.white);这类方法往往也可以通过索引来作为参数,使用字符串只是能显示的更加直观,但是当我们传递字符串时,程序内部会进行一些处理,频繁调用的话可能就会造成性能的消耗。因此我们可以先找到对应的索引,并将其缓存起来,供后续使用,如下:
int idleHash = Animator.StringToHash("Idle");
animator.SetTrigger(idleHash);
int colorId = Shader.PropertyToID("Color");
material.SetColor(colorId, Color.white);缓存引用对象