分享一个极简的资源释放解决方案

分享一个极简的资源释放解决方案

本文实现基于Cocos Creator 3D v1.2.0
Creator 3D v1.2.0 demo:https://forum.cocos.org/uploads/short-url/i3qOaa5QFBwVXuLSba7Ru2WQJkt.rar
Cocos v2.2.2 demo ResCleaner-cocos-v222.zip|attachment (446.5 KB)

场景的资源自动释放是有问题的,官方已经修复了。补丁地址:<https://github.com/cocos-creator/engine/pull/7619 >

特点

  • 使用简单,无管理负担。
  • 项目接入成本低,只需要处理对象池部分即可。
  • 性能消耗跟场景上的节点数成正比。

原理


释放逻辑如下:

  1. 遍历场景上所有节点,搜集每个节点上所有组件引用的资源。
  2. 收集所有正在加载中的资源(loader.loadRes、loader.loadResArray)
  3. 遍历资源缓存(loader._cache)。如果当前资源既没有被场景节点引用又不属于加载中则释放。

代码讲解

核心代码如下:
在这里插入图片描述

另外,代码中有部分函数是从引擎源码(auto-release-utils.ts)中拷贝出来的,因为引擎没有对外暴露这些函数。
在这里插入图片描述

难点在于加载中资源的剔除。大致逻辑如下:首先获取所有加载中的加载队列。然后对加载队列依赖的资源进行递归资源引用查找。

项目接入

  1. 引入脚本文件ResCleaner.ts到项目当中

  2. 检查项目所有使用对象池的地方。如果完全没有使用到对象池直接跳到step4。否则执行step3.

  3. 由于引擎内置的NodePool在节点回收的时候会从场景上移除,导致节点无法被资源清理函数遍历到。所以需要自己开发一个对象池。新实现的对象池需要利用node.active = false来避免使用node.removeFromParent()。样例如下:
    直接使用一个数组存储相同预制体
    在这里插入图片描述

  4. 调用资源清理函数 ResCleaner.clean()。调用时机建议在场景切换之后,也可以在收到
    内存不足告警之后调用。

释放效果演示

测试代码如下:
在这里插入图片描述

执行流程:
在start里面开始加载预制体
加载完成后实例化成节点并添加到场景上
调用资源清理函数
将节点移出场景并销毁
调用资源清理函数
将成员变量spframe对资源的引用置空
再次调用资源清理函数

MainCity场景初始状态
在这里插入图片描述

spframe初始资源引用
在这里插入图片描述

prefabA内容
在这里插入图片描述

打印的日志如下:
在这里插入图片描述

代码和日志结合起来看
在这里插入图片描述

图解一下整个过程:
初始
在这里插入图片描述

预制体加载完成成
在这里插入图片描述

实例化成节点并添加到场景上
在这里插入图片描述

调用资源清理后
在这里插入图片描述

节点销毁后
在这里插入图片描述

调用资源清理后
在这里插入图片描述

调用 this.spframe = null
在这里插入图片描述

调用资源清理后
在这里插入图片描述

注意事项

  • 节点如果要复用请使用node.active = false替代node.removeFromParent()。
  • 以下几种情况资源引用不会被统计到
    1. 使用非组件脚本引用资源。如果类不是继承自Component,就无法挂在节点上,也就无法被统计到。
    2. 在组件脚本中间接引用资源。出于性能考虑不支持。
    3. 使用组件的静态成员变量引用资源。感觉用的不多所以暂不支持。

更多文章
个人博客: https://blog.csdn.net/u014560101
公众号:游戏开发之旅
在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值