SpriteFrame引用计数疑问


一个prefab里面只放了一个Sprite

点击按钮执行一次加载prefab,并实例化添加到节点上,多次点击看到,创建的sprite是会增加的,而sprite上的SpriteFrame没有增加,多个sprite的SpriteFrame指向的都是同一个,但是SpriteFrame的引用计数却没有增加,只在第一次点击时prefab,sprite上SpriteFrame的引用计数增加了1,后面不论点击多少次SpriteFrame的引用次数都是1


第一个是没有加载prefab的SpriteFrame 是5个 sprite1个


这是第一次点击加载, sprite3个, SpriteFrame6个,SpriteFrame的引用计数是1
image


点击多次加载后sprite17个, SpriteFrame6个,SpriteFrame的引用计数还是1
image

这是代码
SpriteFrame_Test.rar (3.3 MB)

.addRef() 这个引用计数是要手动增加的

我是直接托在prefab上的,不是属于资源的静态引用吗,而且为什么第一次load prefab 并且instantiate以后正确的,后面再执行就不正确了,我看了prefab的引用次数是会增加的,而里面sprite的也是创建了多个的,而sprite的spriteframe引用次数却不会增加

是不会增加的啊。。他引擎里面写的就是不会增加的

哪里有写?

https://docs.cocos.com/creator/manual/zh/asset/release-manager.html?h=自动释放
这段里面不是写了么

看过去这里的 SpriteFrame 的引用是由 Prefab 来引用。 不是由 instance 出来的实例引用。

但是这样限制了对 UI 层的 SpriteFrame 的替换方案的设计。

理论上动态加载一个 SpriteFrame 后,去替换旧的 SpriteFrame, 旧的 SpriteFrame 需要将引用技术 -1,解除该资源在该实例上的引用。

我只是动态加载了prefab,对于prefab里面的sprite和SpriteFrame不是应该属于静态引用吗,不应该引擎管理吗

不是很懂,看到sprite是由引擎创建多个的,确实也是引用同个SpriteFrame,不是应该新创建一个sprite,SpriteFrame引用计数就加1吗

但是不是哦,cocos官方是想把资源和组件概念拆开吧。资源之间有依赖关系。组件可没有。你节点可以用场景资源或者预制资源实例化出来。此时节点里的组件就用到了资源,但引用计数就要你自己去维护。

官方毕竟还是开发引擎的,不是我们这种用引擎的,文档不够友好,很多东西要去悟他们怎么想的。

对呀,所以预制里面的资源引用计数你不用管他啊,你要想做资源的管理你就在外面管理好你的动态加载资源就行了呗

那我有个资源在预制体里面用了,又在其他地方动态加载了,就不好释放了

内存管理遵循谁加载,谁释放的原则。比如说A预制件上带的spriteFrame是由预制件加载的,那么他的释放就是这个A预制件负责,加入把A挂在B预制件上,那么A的释放就是B负责的。这块引擎已经处理了。所以你不用操心,只是你释放了A,那么spriteFrame的引用计数就会扣。只要你释放了B,就会带着A,A会带着spriteFrame、
你自己动态加载的引用计数,就需要你自己管理。你动态引用了,就有义务在不适用的时候扣掉引用计数。

为什么会不好释放呢?之前那个链接你看了么,里面的“资源的静态引用”部分。假设现在有预制A,资源B,A里面有B。你加载完A之后打印一下资源列表看看计数,然后删除A之后,清除资源看看B是不是也没了;如果在其他地方也加载了B,你就自己弄个计数来管理动态加载的B,如果小于等于0了你就删除资源B,删除的时候检查一下它在资源列表里面的计数是不是0,是0你就释放,不是就说明预制或者其他地方有用到它的,你就不用释放

挖坟回答下我的见解:
首先预制体属于是内置资源,你在上面挂载的所有其他资源资源引用都是静态引用,当我们第一次加载预制体资源时,除了自身会缓存以下,并维护好所有和他静态引用资源的计数引用,所以他的引用资源的ref只会增加1,
当我们通过预制体资源实例化时,只是一个个实例,本质还是由那个被缓存的预制体资源实例化出来的,所以说我们不是手动去清理那个被缓存的预制体资源,他的静态引用资源的引用计数永远不会发生变化,当然你实例化出的预制体只会和缓存预制体资源之间有引用关系,而缓存的预制体资源和静态引用资源才有引用关系,