creator手动资源加载释放管理 想把控好内存释放的同学可以来讨论下

作为写了很多年C++的人来说,管理好内存释放还是很在意的,手动加载的资源要释放干净还是要注意一些东西的,看过坛里一些同学的文章就自己整了个管理器Demo,中心思想还是加载时利用getDependsRecursively获取所有的相关资源然后用引用计数做好记录,释放时通过引用计数去释放来解决多个节点共用资源的问题。
源码地址:https://gitee.com/jinghuashuiyue2017/ResLoadManager/tree/master/ResManager/assets
贴个主要代码:

function ResInfo() {
this.path = “”; //资源路径
this.type = null; //资源类型
this.uuids = {}; //使用的资源id
this.obj = null; //资源对象
this.ref = 0; //引用计数
}

window.ResMgr = {
resPool: {},
uuidTable: {},

//加载资源
LoadRes: function(path, type, callback) {
    if (path in ResMgr.resPool) {
        return false;
    }
    cc.loader.loadRes(path, type, function (err, prefab) {
        //node = cc.instantiate(prefab);
        if (err==null) {
            if (path in ResMgr.resPool) {
                cc.log("loadRes: "+path+" err:already exist");
                if (callback!=null) {
                    callback(err,path);
                }
                return;
            }
            let newInfo = new ResInfo();
            newInfo.path = path;
            newInfo.obj = prefab;
            newInfo.type = type;
            //记录所有相关资源
            for (let key of cc.loader.getDependsRecursively(prefab)) {
                newInfo.uuids[key] = true;
                if (key in ResMgr.uuidTable) {
                    ResMgr.uuidTable[key] += 1;
                }
                else{
                    ResMgr.uuidTable[key] = 1;
                }
                //cc.log(path+"(getDependsRecursively):"+key);
            }
            ResMgr.resPool[path] = newInfo;
        }
        cc.log("loadRes: "+path+" err:"+err);
        if (callback!=null) {
            callback(err,path);
        }
    });
    return true;
},
//获取实例
GetInstance: function(path) {
    let p = this.resPool[path];
    if(p!=null){
        p.ref++;
        if (p.type==cc.Prefab) {
            return cc.instantiate(p.obj);
        }
        else{
            return p.obj;
        }
    }
    return null;
},
GetInstanceArrary: function(path, num) {
    let arr = new Array();
    let p = this.resPool[path];
    if(p!=null && num>0){
        for (let index = 0; index < num; index++) {
            if (p.type==cc.Prefab) {
                arr.push(cc.instantiate(p.obj));
            }
            else{
                arr.push(p.obj);
            }
        }
        p.ref+=num;
    }
    return arr;
},
//释放实例
ReleaseInstance: function(path, num=1) {
    let p = this.resPool[path];
    if(p!=null){
        p.ref -= num;
        //释放资源
        if (p.ref<=0) {
            this._ReleaseRes(p);
        }
    }
},
//释放资源
_ReleaseRes: function(p) {
    //cc.loader.release(Object.keys(p.uuids));
    Object.keys(p.uuids).forEach(function(key){
        //cc.log(key+": "+LoadRes.uuidTable[key]);
        ResMgr.uuidTable[key]--;
        if (ResMgr.uuidTable[key] > 0) {
            delete p.uuids[key];
        }
        else{
            delete ResMgr.uuidTable[key];
        }
    });
    cc.loader.release(Object.keys(p.uuids));
    delete this.resPool[p.path];
}

};

还有些情况还没考虑到,比如由于加载是异步的,加载还没完成的同时去释放相同资源可能会出问题

3赞

楼主的这个方法很好,非常适合单场景游戏,场景上只挂一个入口脚本,不引用资源,ui预设都是动态加载,可以避免场景引用的资源没有计数

对于一些公共资源,和自动图集资源该如何处理呢

在你不需要的时候自己释放

请问一下,我照着楼主这样释放某张图片,在web上跑没问题,但是到开发者工具上就会把这张图片关联的整个图集给释放了,怎么回事