内存管理策略

  |   0 评论   |   0 浏览

一个常见的内存管理策略

  • 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,且时间戳最旧的,卸载掉
  • 其他层,如果需要的话,也可以用类似的模式来写,但也不必要每一层都这样
更进一步供大家思考
  • 高中低配如何区分不同的内存管理策略
  • 当触发内存警告的时候,如何处理
  • 图集也是一个很特别的东西,如何特殊处理它

标题:内存管理策略
作者:kyochow
地址:https://kyochow.github.io/articles/2020/11/07/1604734756556.html