-
Creator 版本:2.0.8
-
目标平台: native
为了减轻内存压力。做到不常用的prefab用了之后就清理。如何正确的处理资源的加载和释放?如何在js层能获取到prefab中资源是被多次引用的?
我自己对已经加载的资源做了引用计数,但是我没有把所有的资源都去预加载。这样就存在,之前使用过的资源被释放了。
@panda
Creator 版本:2.0.8
目标平台: native
为了减轻内存压力。做到不常用的prefab用了之后就清理。如何正确的处理资源的加载和释放?如何在js层能获取到prefab中资源是被多次引用的?
我自己对已经加载的资源做了引用计数,但是我没有把所有的资源都去预加载。这样就存在,之前使用过的资源被释放了。
@panda
我的策略是这样
1、loadres只在一个地方统一处理
2、loadres时我会将这个asset存到一个数组
3、release一个prefab时先获取这个prefab的依赖资源,如果其中有资源在第二步的数组里有被依赖到就剔除这个资源,然后释放
4、我是1.10.2,由于音频的bug,音频不释放,不然可能引起闪退
你能提供一下你资源管理的脚本么?我是在场景没有切换的情况下释放资源的。我也做了资源管理,目前不知道问题出在哪里。
有空贴给你,我这边的做法都是单场景,所有场景都是以预设加载的
我也是单场景,自己做了封装。android对内存开销不严格,但是ios就不行了。
private _cache: { [key: string]: cc.Asset[] } = {};
public async loadRes<T extends cc.Asset>(path: string,
type?: typeof cc.Asset,
category = AssetManager.DEFAULT_KEY,
loadingProgress?: ILoadingProgress): Promise<T> {
let promise = new Promise<T>(resolve => {
cc.loader.loadRes(path, type,
(completed, total) => {
if (loadingProgress) {
loadingProgress.reportMainProgress(completed / total);
}
},
(error, resource) => {
if (error)
console.log(error);
resolve(resource);
if (resource && category)
this.putCache(category, resource);
});
});
return promise;
}
private putCache(category: string, asset: cc.Asset) {
let list = this._cache[category];
let hasCache = false;
if (!list) {
list = [];
this._cache[category] = list;
} else {
for (const cachaAsset of list) {
if (cachaAsset["_uuid"] == asset["_uuid"]) {
hasCache = true;
break;
}
}
}
if (!hasCache)
list.push(asset);
}
releasePrefab(prefab: cc.Prefab) {
this.releaseAssetRecursively(prefab);
}
private releaseAssetRecursively(asset: cc.Asset) {
this.removeCacheAsset(asset);
// 音频不能释放,避免 crash
if (asset instanceof cc.AudioClip) {
// cc.loader.releaseAsset(asset);
return;
}
let deps = cc.loader.getDependsRecursively(asset);
let total = deps.length;
// 当前场景依赖的资源不能释放
let scene = cc.director.getScene();
let sDeps = scene["dependAssets"];
for (const cDep of sDeps) {
let idx = deps.indexOf(cDep);
if (idx >= 0) {
deps.splice(idx, 1);
}
}
for (const key in this._cache) {
if (this._cache.hasOwnProperty(key)) {
const list = this._cache[key];
for (let i = 0; i < list.length; i++) {
let cacheDeps = cc.loader.getDependsRecursively(list[i]);
for (const cDep of cacheDeps) {
let idx = deps.indexOf(cDep);
if (idx >= 0) {
deps.splice(idx, 1);
}
}
}
}
}
cc.loader.release(deps);
console.log(`Release asset [${asset.name}] with ${deps.length}(${total}) dependencies.`);
}
private removeCacheAsset(asset: cc.Asset) {
for (const key in this._cache) {
if (this._cache.hasOwnProperty(key)) {
const list = this._cache[key];
for (let i = 0; i < list.length; i++) {
let cacheAsset = list[i];
if (cacheAsset == asset) {
list.splice(i, 1);
break;
}
}
}
}
}
释放的时候,不能把被依赖的资源释放
如果这个prefab中的资源没有被依赖,然后我释放了。再loadres这个prefab会出现黑屏。就是出现资源丢失,是因为cache里这个prefab没有被删除,然后我拿的是cache里的?方便加qq探讨一下么?710260185
是因为图片被你释放了,但是cc.loader里面缓存还在,这时候cc.loader会直接返回cache
这种情况,你怎么处理的?
我有处理这种情况,例如你加载了a预设,在a预设跑的时候又加载了b图片,那么在a释放时要把b也释放了
prefab里只用了一次的静态资源,是不是就没办法释放了。cache没法清啊。
你的代码贴出来看一下
//资源计数
/**
*
* @param res cc.Texture2D cc.Prefab cc.SpriteAtlas
*/
resRetain(res){
let des = cc.loader.getDependsRecursively(res);
if(des)
{
for(let i = 0 ; i < des.length;++i)
{
let path = des[i];
if(!this._resMap[path])this._resMap[path]=1;
else ++this._resMap[path];
cclog.d("----path:%s-----count--->%d",path,this._resMap[path]);
}
}
}
//释放渲染计数为1的
/**
*
* @param resPath cc.Texture2D cc.Prefab cc.SpriteAtlas
*/
resRelease(resPath)
{
let resTag = cc.loader.getRes(resPath);
if(!resTag){
cclog.d("----该资源没有加载过--->",resPath);
return;
}
let reclyList=[];
let des = cc.loader.getDependsRecursively(resTag);
for(let i = 0 ; i < des.length;++i)
{
let path = des[i];
let resType = cc.loader.getRes(path);
if( resType instanceof cc.Texture2D
|| resType instanceof cc.Prefab
)//|| resType instanceof cc.SpriteAtlas
{
if(this._resMap[path] && --this._resMap[path]<=0)
{
reclyList.push(path);
delete this._resMap[path];
}
}
}
reclyList.length>0 && cc.loader.release(reclyList);
},
我猜你把Textrue2d释放了,但是spriteframe却没有释放,所以黑了
//把缓存中 存储的删掉 也不行。。
let id = cc.loader._getReferenceKey(resTag);
if(cc.loader.getItem(id)){
cc.loader.removeItem(id);
}
不是,resRelease这个方法,你只释放了两种类型的资源,试着把这个判断去掉试试
判断去掉 就出现 prefab 加载失败,prefab 中对象创建失败。 应该是关联的资源被释放造成的。
我查查我这面 关联引用 的资源。