Png 图片的加载和内存释放

    addPng: function () {
        cc.loader.loadRes("btn/btn1", cc.SpriteFrame, function(err, sp) {
            if (err) {
                cc.log("------ err = ", err)
                return;
            }

            let node = new cc.Node()
            let sprite = node.addComponent(cc.Sprite)
            sprite.spriteFrame = sp
            node.name = "Hello"
            this.node.addChild(node)

            // let sc = cc.loader.getRes("btn/btn1")
            // cc.log("------sc = ", sc)
        }.bind(this))
    },
    removePng: function () {
        let node = this.node.getChildByName("Hello")
        if (node) {
            node.removeFromParent()
            cc.loader.releaseRes("btn/btn1")
        }
    },

creator版本 1.3.2 macOS 10.12.1 WEBGL

有两个按钮,分别控制上边两个方法,先添加一个png,并显示在界面,显示正常,然后点击删除按钮,从界面移除,并释放png资源,然后再次点击加按钮,图片不能正常显示,显示黑框,浏览器警告如下

[.Offscreen-For-WebGL-0x7fcfdd8e1800]RENDER WARNING: there is no texture bound to the unit 0
(index):1 WebGL: too many errors, no more errors will be reported to the console for this context.

难道释放资源不能这么用吗?求解答?

RelaseMem.zip (604.9 KB)

demo

试了下 在1.3.0版本是正常的 @panda

hi,这是因为 loadRes("btn/btn1", cc.SpriteFrame ... 获取的是 SpriteFrame 资源,而 releaseRes("btn/btn1") 释放的是 Texture2D 资源本身,并没有释放 spriteFrame,所以再次加载的时候,获取到了之前缓存的 spriteFrame,而它的贴图其实已经删除了。问题的根本还是因为一个 url 可以对应不同 type 的多个资源。

你可以这样做:

var spriteFrame = node.getComponent(cc.Sprite).spriteFrame;
var deps = cc.loader.getDependsRecursively(spriteFrame);
cc.loader.release(deps);

谢谢@panda 这样是可以的

getDependsRecursively是什么意思,@panda

获取依赖资源包括它自身的uuid 1.3.1之后才有的api,返回的是uuid数组,可以看下cc.loader.release()方法说明。

请教下panda,SpriteFrame有没有一个类似于textureCache的缓存,可以依据一个URL删除对应的SpriteFrame ?

SpriteFrame 也是一种资源,可以用 loader 来释放

cc.loader.releaseRes(spriteFrameUrl, cc.SpriteFrame);

也可以直接用

cc.loader.release(spriteFrameObj);

panda 好,1. 用 cc.loader.releaseRes(spriteFrameUrl, cc.SpriteFrame); 这个API ,报错误 CCDebugger.js:350 Resources url ‘url’ does not exist 。 这个spriteFrame 是通过远程URL加载的获得texture,再new cc.SpriteFrame(tex);生成的。如

if (!cc.sys.isNative) {
cc.loader.load(url, function(err, tex){
if( err ){
cc.error(err);
}else {
if(filetype==null){
filetype=1;
}

           cc.vv.textureCacheLRU.putByType(url,"type"+filetype);

           var spriteFrame = new cc.SpriteFrame(tex);
           if( spriteFrame ){
             
                if(callback){
                  callback(spriteFrame);
                };
           }
        }
    }  );

}

2.因为程序中用了大量的图片,而且是从服务器加载的,自己写了一个LRUCache来管理texture,现在仅删除texture,重新加载的时候,会出现黑框的情况。因为没有删除对应的spriteFrame,要如何把需要删除的texture对应的spriteFrame也一起删除掉? 通过 cc.loader.releaseRes(spriteFrameUrl, cc.SpriteFrame); 删除失败了。

releaseRes 适用于项目中 resources 文件夹下的动态资源,不适用于远程资源,请直接用

cc.loader.release(spriteFrame);

谢谢,正常使用cc.loader.release(spriteFrame)删除SpriteFrame删除 没有问题。

但是我在使用过程中出现这个错误,

介绍下应用场景,从服务器动态的下载图片,图片数量非常多几千上万张,所以需要自己控制加载和释放纹理和SpriteFrame的的时机。 纹理我可以自己通过TextureCache 来处理。但是SpriteFrame释放出现错误。
释放错误,是因为生成SpriteFrame 后,我把SpriteFrame也放到{}字典缓存起来了,释放Texture的时候同时用cc.loader.release(spriteFrame) 释放SpriteFrame出上面的错误。

请问,

  1. 上面的错误,是啥情况。

2.知道以前版本有SpriteFrameCache,可以自己来管理SpriteFrame,如果要自己把将旧版本中的 CCSpriteFrameCache.js 来用,仅从1.3版本拷贝 CCSpriteFrameCache.js 文件就可以直接用吗?

3 在1.4.2版本后, 建议如何来自己控制SpriteFrame释放 ?

程序之前因为内存满core掉,然后就直接写了一个LRUCache管理纹理,因为SpriteFrame 没有同时释放,重新用的时候,然后黑屏,现在是想解决这个黑屏的问题,所以在这个贴子下请教,感谢帮助。

TextureCache 和 SpriteFrameCache 中保存的 texture / spriteFrame 引用都只是额外的引用而已,资源本身都是在 cc.loader 中管理的,从 texture cache 中删除并不能彻底移除内存中的 texture,不管什么资源,都必须要依赖 loader 来处理资源释放(loader 会将 texturecache 中的引用删除)。这也是我们删除 sprite frame cache 的原因,它已经没有意义了。

SpriteFrame 和 Texture 是两种资源,不要混在一起,对于 SpriteFrame,如果你用 cc.loader.load 加载远程 texture 之后,应该是单独创建 sprite frame 把?你自己创建的 sprite frame (new cc.SpriteFrame)并不是通过 loader 管理的,自己管理好就行了。你需要的是释放 Texture 的同时把依赖于这个 texture 的 SpriteFrame 给删除,避免后面再用到,否则就会出现黑屏的问题。

我不知道 LRUCache 做的是什么工作,不过 texture 的删除就是用你加载时的远程 url 来去从 loader 中删除: cc.loader.release(remoteUrl);

明白了。 LRUCache 保存了按类型分类的最近使用了texture 的url ,以便删除超过纹理数量最近未使用的texture 。Texture之前就是用 cc.textureCache.removeTextureForKey( url) 删除的,你是说也不需要用这个,仅用cc.loader.release(remoteUrl);就可以是吧?

不需要 removeTextureForKey

我也 1.9.1 遇到这问题了,我这边的图片是从远程 url 动态加载的,然后释放的时候,释放失败,并且报错:

然后,我尝试直接释放相应的 spriteFrame ,就报 webgl 错:

求解。。跪求解。。。我哪里的姿势不对吗??