我要吐槽:内存管理篇

槽点:1、从来没有见过成熟引擎有这么任性!!!!想杀就杀!!
/**
* Release texture.
* @method releaseTexture
*/
releaseTexture: function () {
if (this._webTextureObj) {
cc._renderContext.deleteTexture(this._webTextureObj);
}
},

texture管理是引擎内存管理的第一步,把猴子扔给引擎使用者,使用者焦头烂额,项目稍复杂点便理不清楚,在底层解决这个其实很简单,哪怕引用计数也可以啊
2、引擎鼓励使用NodePool是没有错,但是这个NodePool也太简陋了,不支持多个对象使用,每个对象需要new 一个对象池,太烦了,在具体实现的时候使用了reuse\unuse,可是它的其他组件呢?它的子呢?后来加了一个poolHandlerComp,又是把猴子扔给引擎使用者?
对于一个优秀的对象池,使用者只需要get\put,不需要去自行new 对象(对象构造本身就对对象池兼容),然后不用再put进去,有相应的对象上限处理机制(比如按时间排序)。
3、cocos对资源根本就没有进行管理,简单用一个cache把资源存储起来,提供了一两个释放接口,提供一个autoRelease的标志给用户,然后不顾一切地杀!没有资源分组,没有资源分类,没有上限管理。话说这种东西有技术门槛吗?

1赞

瞧你说的这么牛逼,可以写个插件解决这个问题啊,引擎是开源的。

感觉楼主提的非常好,肯定是在实际中遇到过这些问题

只会js的程序员(不管是搞游戏的还是搞引擎的)搞内存管理就是搞笑

有谁说过他们是成熟引擎吗(逃

虽然我也很想吐槽他们的代码质量!
但毕竟吃人家的嘴软!

比如:

在native上居然每用一个ArmatureDisplay都要新创建一个新的工厂类!
我也是服了(解决问题完全没有从更本上解决,只是随手一写就搞定)
估计他们就是给那些做做小游戏的人用的!
大公司的话估计都把代码改了的吧!

用他们的东西你的靠自己!靠自己去封装!

开源就不用讨论代码质量了吗?开源不开源都不能逃避对代码本身的苛求。

2赞

楼主发的实现是 web 实现,我们在 native 层的确是依赖引用计数机制的,gl texture 并不会随意被释放,只要有对象引用都是安全的。在 web 端,纯 JS 层,我们的确没有找到好的方法来跟踪 texture 的使用,引用计数怕是不行的,JS 层无法在 JS 对象被释放时做任何操作,也无法得知释放的时机。我们固然可以封装一个 destroy 来强制调用,做引用的统计,但是用户只要添加一个自己的引用就破功了。

如果各位有什么好的想法欢迎讨论。

这个你真的说对了,还真是把责任抛给用户,这个 NodePool 是我写的,我确实没信心做出一个完备,可靠的自动对象池管理。想想用户在推入池子和重新获取对象时想要的各种千变万化的表现,我就怕,所以我想,还是交给你们自己去处理的好。至少现在的 NodePool 是足够简单,易理解的,只是无法代替你做你需要做的工作。

从 Cocos2d-JS 开始,到做 creator 的时候,我个人对于 JS 中使用不同的 cache 来缓存资源引用是深恶痛绝的,所以 creator 中的 loader 用来管理所有的资源。这样对于资源的管理就直接了:

  1. 需要加载的资源,loader 会查看自己有没有缓存,没有就启动加载流程,有就用缓存
  2. 需要释放的资源,用户可以通过 loader 来进行释放,不需要关心有没有其他的 cache(当然,用户自己缓存的话还是需要自己处理)

至于不顾一切的杀这一点,我想你抱怨的还是跟第一点一样,没有一个类似引用计数的机制来保障资源不再被使用了,事实上,的确没有找到能够实现资源引用计数的方法,如果大家有办法,还望分享出来。

2赞

不太明白 JavaScript 怎么引用计数?引擎根本不知道用户用了这个贴图没有。
我能想到一些比较靠谱的方案,不过我们还在讨论中,不像你说的那么简单。

要我说的话,引擎就不应该提供对象池,典型的吃力不讨好的模块。会用对象池的根本不屑于用你这个,他自己分分钟能写一个更满意的。

3赞

我想请教下,资源分类后,能够用来做什么呢?
资源的上限管理又是用来做什么的?

希望能有个详细的内存管理文档,现在的文档和api看的都不是很全面,感觉比较迷糊
比如如何《手动》释放,下面的问题
1。场景里node静态引用的的图片和二进制等资源如何释放
2。手动resload加载的图片和二进制等资源
3。手动resload加载的预制以及这个预制引用的资源
4。预制instance生成的实体以及这个实体引用的资源

暂时就想到这么多了

嗯,这方面的确需要文档进一步描述清楚我们的设计思路

注释写的很清楚了,不这样做的话,Mac 平台在关闭程序的时候会报错。也就是说 Mac 模拟器点击关闭就会提示崩溃。

我跟 DragonBones 官方沟通过,这个问题是因为 DragonBones 的 cpp runtime 中,CCFactory.getFactory() 返回的单例是一个对象,而不是指针。这个对象与 WorldClock 的一个静态变量(另外一个单例,也是对象),存在释放顺序的问题(两个静态变量无法保证释放顺序,从而导致报错)。

所以,为了避免这个崩溃才这样做的。如果要彻底解决,需要 DragonBones runtime 中将 CCFactory 的单例改为指针,并且在程序结束时(需要在引擎的 Director 中来处理)主动释放。

这和语言没有关系,js自己的对象本身不在讨论的范畴,而texture是由引擎创建与delete的,这部分应该规范起来,首先保证除了loadRes之外的资源能够走正常的释放,然后对于loadRes的资源强制让用户走释放通道,如果用户自己不走用释放通道那就残留在里面,用户至少是有方法解决,现在的autoRelease是不顾一切地强杀,用户得去理清楚资源嵌套,这很容易误杀

这个看定位,如果定位为一个渲染库,那么没有对象池也没有关系

这个我知道,我也这样改了!
但是解决问题的话,应该按你说这这种方法去解决,而不是这样随手一写,这看似解决了问题
但是留有隐患!

怎么规范呢?用户可以用 js 持有 texture 对象,你如何做引用计数?

除了loadRes之外的资源能够走正常的释放是行不通的,因为你不知道用户是否会在 js 层持有场景中的静态资源。如果你正常释放,那就会出现你最开始吐槽的 texture 被 delete 了,然后就变成了你说的“从来没有见过成熟引擎有这么任性!!!!想杀就杀!!”

auto release 只是一个辅助手段,不是一个默认启用的选项,本身局限性很大文档也用中英文都写得很清楚了。目前更推荐的是手动管理内存。

你说的机制类似于早期 OC,需要用户主动使用 retain / release 吧?这也是一个方案,retain / release 有一个大家熟知的问题,就是用户管理起来依然很容易出错,前后匹配不上导致泄漏,或者是误删。这个出错的概率和现在需要用户理清楚资源嵌套的错误率,我真的不确定哪个更高

C++ 底层是 DragonBone 官方实现的,有 bug 我们只能绕开 bug,然后跟他反馈,没办法帮他重写。

资源上限管理,用来解决在极端环境下,选择性地保留资源,比如说你有一个UI界面A初始化打开很慢,所以你没有立马释放它,但是随着用户打开的其他UI越来越多,达到一个阀值,那么有一种机制去释放UI界面A,这里只是拿UI来举例,实际上不限于此。