CocosCreator通用框架设计之资源管理

论坛 期权论坛     
niminba   2021-5-15 21:02   46   0
<p>如果你想使用Cocos Creator制作一些规模稍大的游戏,那么资源管理是必须解决的问题,随着游戏的进行,你可能会发现游戏的内存占用只升不降,哪怕你当前只用到了极少的资源,并且有使用cc.loader.release来释放之前加载的资源,但之前使用过的大部分资源都会留在内存中!为什么会这样呢?</p>
<h2>cocos creator 资源管理存在的问题</h2>
<p>资源管理主要解决3个问题,资源加载,资源查找(使用),资源释放。这里要讨论的主要是资源释放的问题,这个问题看上去非常简单,在Cocos2d-x中确实也很简单,但在js中变得复杂了起来,因为难以跟踪一个资源是否可以被释放。</p>
<p>在Cocos2d-x中我们使用引用计数,在引用计数为0的时候释放资源,维护好引用计数即可,而且在Cocos2d-x中我们对资源的管理是比较分散的,引擎层面只提供如TextureCache、AudioManager之类的单例来管理某种特定的资源,大多数的资源都需要我们自己去管理,而在cocos creator中,我们的资源统一由cc.loader来管理,大量使用prefab,prefab与各种资源复杂的引用关系增加了资源管理的难度。</p>
<h2>资源依赖</h2>
<p>资源A可能依赖资源B、C、D,而资源D又依赖资源E,这是非常常见的一种资源依赖情况,如果我们使用<code>cc.loader.loadRes("A")</code>加载资源A,B~E都会被加载进来,但如果我们调用<code>cc.loader.release("A")</code>则只有资源A被释放。</p>
<p style="text-align: center;"><img alt="" src="https://beijingoptbbs.oss-cn-hangzhou.aliyuncs.com/jb/2426819-f8a0df65bef74cc5fcb296104927291c"></p>
<p>每一个加载的资源都会放到cc.loader的_cache中,但cc.loader.release只是将传入的资源进行释放,而没有考虑资源依赖的情况。</p>
<p>如果对cc.loader背后的资源加载流程感兴趣可以参考: https://www.cnblogs.com/ybgame/p/10576884.html</p>
<p>如果我们希望将依赖的资源也一起释放,cocos creator提供了一个笨拙的方法,<code>cc.loader.getDependsRecursively;</code>,递归获取指定资源依赖的所有资源,放入一个数组并返回,然后在cc.loader.release中传入该数组,cc.loader会遍历它们,将其逐个释放。</p>
<p>这种方式虽然可以将资源释放,但却有可能释放了不应该释放的资源,如果有一个资源F依赖D,这时候就会导致F资源无法正常工作。由于cocos creator引擎没有维护好资源的依赖,导致我们在释放D的时候并不知道还有F依赖我们。即使没有F依赖,我们也不确定是否可以释放D,比如我们调用cc.loader加载D,而后又加载了A,此时D已经加载完成,A可以直接使用。但如果释放A的时候,将D也释放了,这就不符合我们的预期,我们期望的是在我们没有显式地释放D时,D不应该随着其它资源的释放而自动释放。</p>
<p>可以简单地进行测试,可以打开Chrome的开发者模式,在Console面板中进行输入,如果是旧版本的cocos creator可以在cc.textureCache中dump所有的纹理,而新版本移除了textureCache,但我们可以输入cc.loader._cache来查看所有的资源。如果资源太多,只关心数量,可以输入Object.keys(cc.loader._cache).length来查看资源总数,我们可以在资源加载前dump一次,加载后dump一次,释放后再dump一次,来对比cc.loader中的缓存状态。当然,也可以写一些便捷的方法,如只dump图片,或者dump与上次dump的差异项。</p>
<p style="text-align: center;"><img alt="" src="https://beijingoptbbs.oss-cn-hangzhou.aliyuncs.com/jb/2426819-d3c8e4e1aa8207067bc979ae3d564c9f"></p>
<h2>资源使用</h2>
<p>除了资源依赖的问题,我们还需要解决资源使用的问题,前者是cc.loader内部的资源组织问题,后者是应用层逻辑的资源使用问题,比如我们需要在一个界面关闭的时候释放某资源,同样会面临一个该不该释放的问题,比如另外一个未关闭的界面是否使用了该资源?如果有其他地方用到了该资源,那么就不应该释放它!</p>
<h2>ResLoader</h2>
<p>在这里我设计了一个ResLoader,来解决cc.loader没有解决好的问题,关键是为每一个资源创建一个CacheInfo来记录资源的依赖和使用等信息,以此来判断资源是否可以释放,使用ResLoader.getInstance().loadRes()来替代cc.loader.loadRes(),ResLoader.getInstance().releaseRes()来替代cc.loader.releaseRes()。</p>
<p>对于依赖,在资源加载的时候ResLoader会自动建立起映射,释放资源的时候会自动取消映射,并检测取消映射后的资源是否可以释放,是才走释放的逻辑。</p>
<p>对于使用,提供了一个use参数,通过该参数来区别是哪里使用了该资源,以及是否有其他地方使用了该资源,当一个资源即没有倍其他资源依赖,也没有被其它逻辑使用,那么这个资源就可以被释放。</p>
<div class="blockcode">
<pre class="brush:js;">
/**
* 资源加载类
* 1. 加载完成后自动记录引用关系,根据DependKeys记录反向依赖
分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:1060120
帖子:212021
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP