Unity3D 内存优化(一)对象池

一、定义:

关于U3D内存优化,一直是游戏开发者头疼的事情,由于在项目中我们会频繁地创建和销毁一些对象,例如:怪物模型或者是UI预设体,但是,部分对象在游戏中是会频繁出现的,例如战斗中的小怪物,假如每次都在使用的时候创建新对象,使用完毕后又直接销毁,这样对于游戏的内存消耗是很巨大的。

设想一下,我们是否能做一个池子,将一些常用的对象在创建之后放入池中,每次使用都直接从池子中查找获取,这样在提高对象利用率降低重复创建对象时的内存消耗的同时,对于性能提高有很大的帮助,这样的池子就是我们所要说的——对象池

对象池——就是将对象存储在一个池子中,当需要时再次使用,而不是每次都实例化一个新的对象。


二、使用对象池有几个注意点:

1.虽然对象池可以优化对象利用率,但是对象池也不能无限地存储对象,这样对于内存占用也是急剧增加,应该通过限制池子上限,并通过统计获取使用频率较低的对象并剔除,从而动态地收缩对象池;

2.对于重复使用的对象,在对象池中应该处理好对象重置(reset)的操作;

3.假如在多个线程中同时访问统一对象池,要处理好线程安全的问题。

三、实践:

关于对象池的内存优化,我们可以参考内存池的设计模式:内存池设计与实现

具体如何设计对象池,我们可以通过从AssetStore获取成熟的插件,例如:

PoolManager,具体使用方法:Unity3D研究院之初探PoolManager插件(七十四)

当然我们也可以设计自己的对象池框架:Unity3D内存管理——对象池(Object Pool)


具体步骤:

1.将插件.unitypackage包导入工程中;

2.在Hierachy中新建一个Empty对象,选中该Empty对象,然后选择菜单栏的Component—>Path-o-logical—>Pool Manager—>Spawn Pool:

        Unity3D 内存优化(一)对象池_第1张图片

3.完成上述步骤后,在Empty对象下会绑定一个Spawn Pool组件,接下来我们就需要进行基本的信息设置:

        Unity3D 内存优化(一)对象池_第2张图片

       同一个对象池可以存放不同预设体,每个预设体我们都可以为其创建一个类型栏,同一预设体创建出来的对象归属于同一栏。

4.Spawn中各个属性的作用:

PoolName:缓存池的唯一名称。

MatchPoolScale:勾选后实例化的游戏对象的缩放比例将全是1,不勾选择用Prefab默认的。

MachPool Layer:勾选后实例化的游戏对象的Layer将用Prefab默认的。

Don’t Reparent:勾选后实例化的对象将没有父节点,通通在最上层,建议不要勾选。

Don’t Destroy On Load:这个就不用我解释了吧?切换场景不释放。

Log Messages: 是否打印日志信息

Pre-Prefab Pool Options :缓存池列表,意思就是缓存列表里面可以放各种类型的Prefab。右边有个 “+”按钮点击就添加每个类型的Prefab了

prefab:可以直接把工程里的Prefab直接拖进来。

preloadAmount:缓存池这个Prefab的预加载数量。意思为一开始加载的数量!

preloadTime:如果勾选表示缓存池所有的gameobject可以“异步”加载。

preloadFrames:每几帧加载一个。

preloadDelay:延迟多久开始加载。

limitInstance:是否开启对象实例化的限制功能。

limit Amount:限制实例化Prefab的数量,也就是限制缓冲池的数量,它和上面的preloadAmount是有冲突的,如果同时开启则以limitAmout为准。

limitFIFO:如果我们限制了缓存池里面只能有10个Prefab,如果不勾选它,那么你拿第11个的时候就会返回null。如果勾选它在取第11个的时候他会返回给你前10个里最不常用的那个。

cullDespawend:是否开启缓存池智能自动清理模式。

cull Above:缓存池自动清理,但是始终保留几个对象不清理。

cull Delay:每过多久执行一遍自动清理,单位是秒。从上一次清理过后开始计时

cullMaxPerPass:每次自动清理几个游戏对象。

自动清理:就是当池子里面的对象setActive(false)也就是目前不用的时候,poolManager会根据上述参数自动清理这些对象,清理也就是Destroy()掉。

active变为true或false是由Spawn和Despawn方法决定的!

limitInstance是否开启(打钩)的区别:

不开启情况:假如此时preloadAmount为1,如果用户想要每隔5秒去Spawn一个缓冲池中的对象,那么当加载第二个prefab对象的时候,缓冲池会再创建一个此对象,如果程序再Spawn,那么还会在产生一个这样的对象,就这样一直产生下去,Spawn几次就产生几个对象!

(粒子系统:循环时:Spawn几次,就会产生几个对象,不循环时(循环结束状态为false):会再产生一个对象,如果此时的Spawn速度特别快,并且检测不到前面的对象状态为false,那么可能会产生多个对象,直到检测到前面的几个对象有false状态,那么产生对象到此为止,程序在此几个对象之间来回Spawn!)

开启情况:

此时Limit Amount为1

limitFIFO勾选:那么程序永远使用的是预加载对象,而不会再产生其他对象!当加载第二次的时候,即使第一个对象处于true状态,也使用它,即操作第一个对象!(粒子系统为循环或者不循环时,效果和这一样)

limitFIFO不勾选:那么程序永远使用的是预加载对象,而不会再产生其他对象!当加载第二次的时候,那么必须等第一个对象变为false状态,才能使用它!如果过了5s,第一个对象还没变为false状态,那么程序会报错!(粒子系统为循环:会循环下去,只有一个预加载对象,不报错,不循环时:等上一个变为false才能进行第二次,只有一个预加载对象,不报错!)

如果limit Amount数量大于1,为10的话

limitFIFO勾选:永远只有10个对象产生,当加载第11个对象时,如果前十个对象没有一个active为false状态,那么程序会选择不常用的那个,从而避免报错!

limitFIFO不勾选:永远只有10个对象产生,但是当加载第11个对象时,如果前十个对象没有一个active为false状态,那么程序会报错!

(粒子系统,永远只有10个对象,不报错!)

5.设置完以上参数之后,我们开始在代码中进行对象添加到对象池和从对象池中取出对象的操作:

    a. 获取对象池:

private SpawnPool mActors_Pool;

mActors_Pool = PoolManager.Pools["ActorsAndBullets"];

    b.获取对象池中对象的方法:

Transform bulletPrefab = mActors_Pool.prefabs["Bullet"];
Transform bullet = mActors_Pool.Spawn(bulletPrefab);

    c.销毁对象池中对象的方法:

mActors_Pool.Despawn(bullet);

    d.全部销毁的方法:

mActors_Pool.DespawnAll();

你可能感兴趣的:(技术笔记)