内存管理策略
一个常见的内存管理策略
- LEVEL-1 AssetBundle管理
- LEVEL-2 Asset管理
- LEVEL-3 实例管理(Pool管理)
各层之间的策略是如下的(每个人思路不同,或许略有差异,但总体相似)
- 逻辑层要一个对象的实例,调用Pool.Spawn(key),例如创建一个npc路人甲
- Pool管理层找这个key的实例池子,如果有,生成一个实例返回,如果没有,到Asset层请求Asset来构建这个key的Pool
- Asset管理层,查找自己有没有这个资源,有就返回,没有,到Bundle层去申请这个key的Asset,并返回
- Bundle检查这个key属于哪个AssetBundle,如果AB已经加载了,从AB里Load这个Asset,如果AB没有加载,到磁盘上加载这个AB,然后再返回这个key的Asset
看起来思路是ok的,但我们不可能把所有的AB都加载到内存,那就必然涉及到加载AB和卸载AB,其中加载没什么好说的,需要的时候必须加载,那问题是:不用的bundle我们什么时候卸载掉呢?
方案1
很自然的,我们就想到了引用计数策略:
- 给Lv1,Lv2,Lv3的每一层个每一个Entity都添加一个引用计数
- 应用层每请求某一个对象,对象池层(Lv3)就分配一个实例给上层,同时引用计数+1,上层每归还一个对象,引用计数就-1
- 对象池层每申请一个Asset来
- 当这个bundle引用计数为0的时候,卸载掉该bundle,简单粗暴够用
相信很多游戏有这么一层已经足够了
但这种做法足够好么?
有一些资源,我们是很频繁的用,那我们用完立刻回收,是否会造成频繁的加载-创建-归还-销毁-加载-创建-归还-销毁的螺旋呢
方案2
已AB层为例,在方案1的基础上
- 给每一个bundle记录一个时间戳,每当有该AB中的资源被使用,更新时间戳到最新
- 定时轮询,引用计数为0的bundle,且时间戳最旧的,卸载掉
- 其他层,如果需要的话,也可以用类似的模式来写,但也不必要每一层都这样
更进一步供大家思考
- 高中低配如何区分不同的内存管理策略
- 当触发内存警告的时候,如何处理
- 图集也是一个很特别的东西,如何特殊处理它