creator mjz内存优化1

一 了解一下creator资源管理

资源文件:30clickpzh1.mp3
meta文件:30clickpzh1.mp3.meta

{
  "ver": "2.0.0",
  "uuid": "963f7894-eaeb-4131-9c88-6188763730c0",
  "downloadMode": 0,
  "subMetas": {}
}

json文件:963f7894-eaeb-4131-9c88-6188763730c0.json

{
  "__type__": "cc.AudioClip",
  "_name": "30clickpzh1",
  "_objFlags": 0,
  "_native": ".mp3",
  "loadMode": 0
}

cc.loader继承PipeLine:这是重点
PipeLine._cache:这个成员变量存储所有缓存的资源
PipeLine.flowIn():push一个data进入_cache
PipeLine.flowOut();pop一个data进入_cache
PipeLine.getItem():get一个data从_cache
PipeLine.removeItem():移除一个data从_cache,这将仅仅从 pipeline 或者 loader 中删除其缓存,并不会释放它所依赖的资源
PipeLine.clear():清空缓存_cache

cc.loader._getResUuid (url, type, mount, quiet):传入资源路径可以获取到这个资源对应的uuid
cc.loader._getReferenceKey (assetOrUrlOrUuid):传入一个uuid可以获取到这个资源的依赖key
(形如res/import/…/uuid.json)
AutoReleaseUtils.getDependsRecursively(key):传入一个key可以获取他的依赖表
cc.loader.loadRes(url,type,…):加载资源
cc.loader.loadResArray(url,type,…);批量加载资源
cc.loader.getRes(url,type):获取_cache中的内容
cc.loader._cache:这是一个加载缓存表,这里面的key就是依赖key,存的值就是对这个资源的解析缓存data
这个data的数据如下:
_owner:
_ownerProp:
complete:是否加载完成
content:真实的资源数据
depended:依赖的key
dependKeys:被依赖的key
id:uuid
url:

这是creator中meta的原理,每一个新的资源都会有用一个唯一的uuid来标记,回为每一个资源生成一个meta文件用来标记它,这里的json文件是对资源文件的深度解析,也可以理解他描述了这个资源文件的依赖信息,比如这个文件是一个预制体,那它会引用很多其它资源,这些其它资源就是他的依赖

二 下面开始讲解

思想:将场景和场景的资源绑定,增加一个场景引用计数+1,移除一个场景引用计数-1

修改load函数:这个作用是可以记录当前场景的资源的加载情况

 public static replaceLoad() {
        let loader = cc.loader as any;
        let originLoad = loader.load;
        loader.load = function(resources: string|string[]|{uuid?: string, url?: string, type?: string}, progressCallback?: (completedCount: number, totalCount: number, item: any) => void, completeCallback?: Function|null, name?: string): void {
            let count = 0;
            if (!completeCallback) {
                completeCallback = progressCallback;
                progressCallback = null;
            }

            ResourceLoader.loadLog && ResourceLoader.loadLog.logResources(resources);
            if (Array.isArray(resources)) {
                resources.forEach((r: any) => {
                    ResourceLoader.addAssetSceneBitWithUuid(r.uuid, name)
                })
            } else if (typeof resources == 'object') {
                ResourceLoader.addAssetSceneBitWithUuid(resources.uuid, name)
            }

            let jobComplete = jobScheduler.createJobCallback(completeCallback)
            let complete = function(err, loaded) {
                if (err) {
                    if (!(ResourceLoader as any)._id) {
                        //未启动成功
                        originLoad.call(cc.loader, resources, progressCallback, complete);
                        return;
                    }
                    if (count < 3) {
                        count++;
                        cc.director.getScheduler().schedule(() => {
                            originLoad.call(cc.loader, resources, progressCallback, complete);
                        }, ResourceLoader, 0, 0, Math.pow(2, count), false);
                    } else {
                        // TODO: 取消所有的加载
                        //this_1.node.emit()
                        UIPopupHelper.showOfflineDialog(Lang.get("login_network_timeout"))
                    }
                    return;
                } else {
                    jobComplete.call(this, err, loaded);
                }
            }
            originLoad.call(cc.loader, resources, progressCallback, complete);
        }
    }

对每一个场景里的资源做引用计数(增加获取移除)

 private static addAssetSceneBitWithUuid(uuid: string, name?: string) {
        let index = ResourceLoader.getSceneBitIndex(name);
        if (index < 0) {
            return;
        }

        let bits = ResourceLoader.resources[uuid] || [];
        let length = Math.floor(index / 64);
        let offset = index % 64;
        let oldValue = bits[length];
        if (oldValue && ((oldValue >> offset) & 1) == 1) {
            return;
        }
        for (let i = bits.length; i < length; i ++) {
            bits[i] = 0;
        }
        bits[length] |= 1 << offset;
        ResourceLoader.resources[uuid] = bits;
    }
 private static removeAssetSceneBitWithUuid(uuid: string, name: string) {
        let index = ResourceLoader.getSceneBitIndex(name);
        if (index < 0) {
            return;
        }

        let length = Math.floor(index / 64);
        let offset = index % 64;

        let bits = ResourceLoader.resources[uuid]
        if (!bits || bits.length <= length) {
            console.warn('资源没有被场景引用:', uuid, name)
            return;
        }

        bits[length] &= ~(1 << offset);
        while(length >= 0) {
            if (bits[length] == 0) {
                bits.pop();
                length--;
            } else {
                break;
            }
        }
    }

1onMemoryWarning
收到微信发来的内存警告时,释放没有被引用的资源和触发js的GC

 public static onMemoryWarning(res: {level: number}) {
        let level = res && res.level || 99;
        cc.warn("onMemoryWarningReceive:", level);
        if (this.memoryWarning == 0) {
            cc.director.getScheduler().schedule(ResourceLoader.releaseUnused, ResourceLoader, 0, 0, 60);
        }
        ResourceLoader.memoryWarning = level;
        let wx = window['wx'] as any;
        wx && wx.triggerGC();
    }
public static releaseUnused() {
        cc.warn("release unused resoures");
        if (this.removeScene && this.memoryWarning > 5) {
            //遍历中会移除key,所以先保存着
            let uuids = Object.keys(ResourceLoader.resources);
            for (let i = 0; i < uuids.length; i++) {
                let uuid = uuids[i];
                this.releaseAsset(uuid);
            }

            this.removeScene = false;
            this.memoryWarning = 0;
        }
    }

    private static releaseAsset(uuid: string) {
        let loader = cc.loader as any;
        let key = loader._getReferenceKey(uuid);
        let item = loader.getItem(key);
        if (!item) {
            return;
        }

        let depended = item.depended;
        if (!item.complete || (depended && depended.length > 0)) {
            return;
        }

        let bits = ResourceLoader.resources[uuid];
        if (bits && bits.length > 0) {
            return;
        }

        let dependKeys = item.dependKeys;

        delete ResourceLoader.resources[uuid];
        loader.release(uuid)
        cc.log("release asset:", uuid);

        if (dependKeys) {
            for (let i = 0; i < dependKeys.length; i++) {
                let depItem = loader.getItem(dependKeys[i]);
                if (!depItem) {
                    continue;
                }
                let depended = depItem.depended;
                depended.splice(depended.indexOf(key), 1);
                if (depended.length == 0) {
                    this.releaseAsset(depItem.uuid)
                }
            }
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值