2.0.2 内存管理方案,哪家强?大家来围观。

看上图(论坛的图片不能放大看的,需要下载下来才能看清楚),有研究过的欢迎来讨论。

希望引擎团队能提供更多资源相关的API。
更希望引擎组能提供一套高效易用的资源、内存管理解决方案。

在论坛有看到引擎组的人有说过,js 引用的资源没办法统计引用计数。
但实际中根本不会用变量去存一个原始资源的引用,即使会那也可以通过调用API进行手动统计啊。

欢迎讨论:QQ744396002

1赞

自己顶一下,有引擎组关注到吗 @panda

赞~ 分析的很好!如果动手能力强的,可以自己对资源依赖这块添加引用计数,资源管理这块已经有扩充人员了,后面版本应该会有所优化的。

统计本身不难,但是我上图想表达的是,释放那些资源后会存在一些问题,这些问题用户没办法自己解决,需要引擎组进行处理。想要绕开异常很简单,就是不要释放那些预制物原本的资源,但这样就不能精准的去控制好内存。
上面的情况,如果创建实例对象时,能够重新去加载缺少的资源,并且可以监听加载了哪些资源,那就好了,为什么要报异常:sweat:

目前提供的这方面的API实在很少,很不好用。

2赞

顶一顶,希望更多人关注这块需求

1赞

mark一下,坐等围观大佬结论~

不支持,也不赞同你自己通过引用计数器的方式管理内存,

你首先要搞明白,node.destroy(),和cc.loader.release 的区别,所以我压根觉得不需要再来一个引用计数器,完全可以通过你自己的逻辑控制创建,或者销毁。所以,我经常看到很多哥们,喜欢每次创建一个prefab或者spriteframe,都通过cc.loader.load,是完全没必要的,上一次还没release,又不停的load(当然其实不需要release,只要保存好那个Class对象或者Texture2d对象的引用,就可以再次创建了),然后怪内存不停涨,是没道理的。

如果你自己的代码多了以后,你自己都是混乱的,那给你一个引用计数器也释放不掉。

另外,你那个图,我实在没看懂,怎么重新创建实例pB,会创建不了,看不懂你那里图示。

只要统一好资源分类和调用的接口,手动管理起来还是比较容易的。唯一的一点就是垃圾回收的延迟,在特定条件下频繁加载释放,会导致短期内内存升高。

1赞

你应该没看懂,或自己没去管理内存,试试你就知道。
从哪里看出没搞懂destroy 和 release 的区别呢? 实例对象destroy后是不会释放掉它依赖资源的内存的,所有动态加载的东西都需要手动去释放。

你说的这些正是我上面说的。

我个人是习惯了手动,把prefab简化之后来说,其实就是资源纹理和资源实例的关系的内存管理,如果在javascript底层自有的垃圾回收器基础上,再来一个资源管理的引用计数器管理,无疑是很牛逼的,类似于Java ,C#这种语言的垃圾回收器,但是前提是不能影响到性能,这个前提下,我感觉别抱太大希望。

从我用过多种开发语言的经验来说,资源的内存管理,都可以确定是手动的,而且,貌似目前全球的程序开发里好像还没有这么一个关于资源管理的引用计数器自动垃圾回收的引擎或语言。

资源引用计数是完全可以实现的,而且也不应该有性能问题。
手动管理,是怎么管理的?N个界面被陆续打开,在经过无数次动态修改了表现内容后,你怎么知道你应该释放哪些资源,能够释放哪些资源?这一定需要有统一的资源管理方案的,时刻都可以知道哪些资源是正在被使用、哪些已经没用,什么时候去释放这些没用的资源也应该有多种策略可以选择。

官方开放这个API cc.loader.getDependsRecursively()、cc.loader.release(uuid),就是想让用户自行管理;自己管理没问题,但仅仅目前提供的API不够用,还有一些情况会引起异常,所以才说现在没办法做到精确控制。

你想的太简单了,这里面涉及一个”图“的算法,巨复杂,我说一个简单的情形:A关联B,B关联C,C关联D,D又关联了B,这时候A不关联B了,那么,BCD要不要销毁?现实的项目越大,那么循环引用的问题是一般都超级复杂,复杂度就体现在这,我这么跟你说,BCD其实销毁(BCD就是一个无用的垃圾)或者不销毁(非必需的对象,可以不回收也可以随时被回收)的情况都有可能发生,但是他们与外界确实没有引用关系了,所以比如C++,OC里就有强引用、弱引用之分。

真实的复杂情况,我相信肯定比这个还要复杂,引用计数导致的性能问题在一些语言里有说过!这里只是我个人愚见,略知皮毛。可能也不完全对

另外,关于手动管理是怎么管理的,这就看你经验了,应该每个程序猿干久了都会有一套属于自己的设计模式习惯,所有才有架构师,有cocos引擎,各种各样的框架。

也许我的想法也不对,说不定Cocos官方大神能搞出你想要的东西,当然也是我想要的,希望吧。

你扯偏了,不是要搞一个像Java的垃圾回收机制(这个Js本身就有了),而是搞个针对资源的管理方案。
资源的加载、销毁、修改,都是明确的,所以它们是可以被正确统计的,统计之后就是对它们做不同的策略进行管理。

官方现在不着急搞一套方案,就是觉得用户自行管理也不是什么难事,确实不难,回到上面说的,“仅仅是目前提供的API不够用,还有一些情况会引起异常,所以才说现在没办法做到精确控制”。

作为引擎的使用者,肯定是希望官方提供一套易用且高效的管理方案:grinning:

和楼主的实现方式一致,也同样遇到资源引用部分被释放导致新的预制无法创建的问题,主要出现在正在加载的预制,其中部分引用由于其他预制的释放而销毁,要正确创建,在加载完成时,需要销毁该预制,在重新加载,才能完成创建

问题原因,应该是在未加载完成预制之前,是不知道该预制所引用到的资源是哪些,而无法做到不释放

如果想对部分纹理进行管理,比如,只对resources/xxx下面的资源进行管理,从哪个API可以获取到依赖项的resources路径呢?
比如,要释放一个prefab所依赖的资源,获取他的依赖项(getDependsRecursively),然后根据获取的依赖项是否存在于resources/xxx路径下面,来释放相关资源。

自己写了一套组件解决了:
https://forum.cocos.com/t/cocos-loader/70501

资源的管理其实并不复杂。真正的内存大户是纹理,纹理,还是纹理。管理好这一块,就都解决了。
可以把纹理对象做成一个黑盒,这个黑盒本身是有loading, unloaded, loaded三个状态的。外部的逻辑其实不需要关心这些状态,也不应该关心这个状态。做好这个,可以让那些什么非纹理的异步加载统统去死。纹理的应用逻辑层面上也没有异步,也不应该有异步。这样用起来也简单,逻辑也不复杂。这个应该是引擎组做的事情。
要知道游戏逻辑层大量异步,会造成逻辑结构过于复杂,难于维护,并且极易出现神坑。

这个方案是可行的,至少在1.8.2上做到了。

还有一种方法,就是引擎组应该把cc.Asset的生命期和持有者都整理和重新设计一下,然后设置一个内存上限值,达到上限时,过期不用的对象要销毁或卸载。
第三种方法,定时扫描所有节点的cc.Asset,找出那些不被使用的对象,然后进行回收,但每次扫描的开销时间较长。

mark一个,刚好最近也在研究这个问题