关于 Spidermonkey v52 升级问题的咨询

你完全可以把很重的东西放在C++里,JS里跑业务逻辑 好像没有什么慢的情况出现。
我也是用COCOS2DX -JSB

主要是绑定代码的修改比较麻烦。

感谢回复,我已经花了两天的时间,手动把 Creator 1.6.2 的 v52 升级对应到了 cocos2dx 3.12 引擎了。

大部分的功能已经对应, mac,Android 的编译运行也都通过了,目前在手动处理 cocostudio 的绑定部分。

后续也许还有什么别的问题,再来咨询官方 :slightly_smiling:

你这叫升级?这是降级啊。。。

额?为什么这么说呢? 我是把 cocos2d-x 3.12 的 SpiderMonkey v33 升级到 v52 为什么说是降级呢?

我理解为,你手动把creator1.6里面的SpiderMonkey v52"升级"到cocos2dx3.12里面的SpiderMonkey v33的版本。

今天继续测试 v52 的升级,期间碰到了几个问题,希望官方可以解惑一下。

  1. 关于 CC_ENABLE_GC_FOR_NATIVE_OBJECTS

在 cocos2d-x 3.1x 中,这个宏默认都是 0,注释也写的是:

By default this behavior is disabled by default

我下载了 Cocos Creator 1.6.2 beta.3,创建了一个 HelloWorld 工程,发现项目中的这个宏,默认是 1,也就是默认是启用的。

然后我试了下把这个宏关掉,再编译,发现会报错,原因是在这个宏不启用的情况下,ScriptingCore 中还残留这 SpiderMonkey v33 的一些函数的调用,如 JS::RemoveObjectRoot , JS::AddNamedObjectRoot

是不是说,在新的 SpiderMonkey v52 环境下,官方已经强制用户使用 CC_ENABLE_GC_FOR_NATIVE_OBJECTS 这种模式了 ?

  1. jsb_RefFinalizeHook_finalize 崩溃问题 (这个最头痛)

这个可能是 cocostudio 绑定造成的问题 。

今天把我 cocostudio 部分的 auto manual 绑定给对应了一下,然后把之前游戏的 ui (json) 文件拿来做了下测试,结果在 jsb_RefFinalizeHook_finalize 的地方会发生崩溃,原因是:

int count = refObj->getReferenceCount();

这里的 count 已经是 0 了,导致,导致后面的 Ref::release 里面,断言失败

CCASSERT(_referenceCount > 0, "reference count should be greater than 0");

对于这个问题,我做了些调查,现在能提供一些信息:

a. jsb_RefFinalizeHook_finalize 触发的时候,正常情况下,refObj 的类型是 cocos2d::Node*, cocos2d::SpriteFrame* 等等。
但是出错的,refObj 的类型显示是:

b. 每次出现这个问题时候,都是因为解析一个 cocostudio ui 的 mainmenu.json 文件造成的,错误堆栈每次都一样 :

c. 在加载这个 mainmenu.json 界面之前,我已经成功加载和显示了一个 login.json 界面 (包含输入框,按钮之类的)。

d. 如果我修改一下 jsb_RefFinalizeHook_finalize 的代码,把 count == 0 的情况先放过:

int count = refObj->getReferenceCount();
if (count == 1)
{
    refObj->autorelease();
}
else if (count == 0) {
    // 放过
}
else
{
    CC_SAFE_RELEASE(refObj);
}

这样的话,界面可以正常的加载显示,并且上面的按钮之类的也可以正常的使用。

P大下周一来解答你吧,帮你强力@panda一下。

感谢,我周末也会再多做一些调查尝试的。

是的

你遇到的 jsb_RefFinalizeHook_finalize 问题触发的时候已经有对象处在非正常状态了,JS 对象仍然存在的情况下其 C++ 引用计数为 0,这个调查没什么特别好的办法,需要在 preprocess macro 中设置 DEBUG_MODE 为 2,这样会打印更多的信息,可以在出错的时候检查 refObj 的指针,然后在历史 log 中搜索这个指针,看看之前是什么类型的对象,再继续研究为什么会发生问题

感谢回复。

上面提的问题已经解决,是一个 jsb_create_weak_jsobject 造成的问题。

经过上一周的测试,这次 v52 合并到 cocos2d-x 3.12 的尝试应该说是成功了,最大的优点就是安卓上的 jsb 计算能力得到了大幅的提升,已经更好的 GC 管理模式。

下次有时间的话,准备把 CocosCreator 1.7 的 JSB 2.0 给合并到 cocos2d-x 3.1x 里面,性能应该还会有更大的提升。

2赞

最近在使用中,发现了一个内存释放的问题,怎么都找不出原因,想要所以想要咨询一下官方 @panda

首先简单概括一下问题,在新的内存模型下,使用一张单独的图片创建 Sprite 后,无法回收释放图片。

下面是重现的步骤和一些说明(我的理解,可能有错的地方):

  1. 创建一个 cc.Sprite
this.sprite = new cc.Sprite("some.png");

这里先创建一个 Sprite 对象。
绑定层会 创建一个 native ref 对象,引用计数为1;并为其设置 jsb_RefFinalizeHook 在 GC 的时候会触发 jsb_RefFinalizeHook_finalize

  1. 添加到场景
this.addChild(this.sprite); // this == layer

这里的 this 是一个普通的 cc.Layer
这句话,native 会做两件事情
a. native 的 ref 引用计数 +1 ,目前为 2。
b. native 会反过来调用 js 中的 registerNativeRef 函数,把 sprite 和 layer 建立引用关系,防止被 GC
相当于 layer.__nativeRefs[0] <==> sprite

  1. 删除 Sprite (不在同一帧进行)
this.sprite.removeFromParent();

这里也会做两件事:
a. native 会调用 releaseScriptObject ,解除 layer.__nativeRefs[0] <==> sprite 的引用关系
b. 引用计数 -1,目前为 1,还不能析构

  1. 手动 GC ( (不在同一帧进行))
ScriptingCore::forceGC();

这里,应该会触发 sprite 的 jsb_RefFinalizeHook_finalize ,在这里,spriteautorelease

  1. 下一个 mainloop,sprite 被析构

  2. 回收 texture

cc.director.purgeCachedData();

这里,removing unused texture some.png 会显示为被回收。

这个是我认为应该发生的正确流程,但是实际上,却不是这么顺利,这个步骤的 4 会发生问题: 无论手动 GC 多少次,sprite 的 jsb_RefFinalizeHook_finalize 也不会被调用。

除非我在第3步,removeFromParent 之后添加:

this.sprite = null;

那么在一下次的 GC 时,sprite jsb_RefFinalizeHook_finalize 才会触发。

这里我的疑问是,如果我有很多这种 引用对象的形式,那是不是说我必须在想要删除回收资源之前,一个一个的将其设置为 null ?这个显然不太合理。

我也尝试了另一种做法:

  1. 不调用 removeFromParent,而是调用(模仿 Scene::cleanup 的做法)
ScriptingCore::releaseAllChildrenRecursive

这样做,在 GC 的时候,sprite jsb_RefFinalizeHook_finalize 也会触发,但是这时 sprite 的引用计数是2,还不会被autorelease。而再次调用 GC,sprite jsb_RefFinalizeHook_finalize 就再也不会触发了,因此 sprite 一直是保持计数1 的状态,无法析构。

希望官方解惑一下,是不是我的理解或是哪里的做法出了偏差,谢谢了 :slightly_smiling:

你描述的过程基本都是正确的,只是你不理解为什么不会触发 this.sprite 的回收。

这个其实很简单,既然 this.sprite 的引用还存在,就说明从 JS 层仍然可以访问到这个 JS 对象,那么它当然就不是垃圾,自然也不会被 GC 回收。

this.sprite = null; 之后,你之前创建的 JS 对象自然就访问不到了,因为没有任何索引了,那么 GC 就会把它当作垃圾回收掉,也就会触发 jsb_RefFinalizeHook_finalize 回调。

其实新内存模型的意义就在于此,只要 JS 对象不被回收,native 对象的引用计数就无法到达 0,无法被释放,这样保证了 JS 和 native 生命周期的一致性。

厉害 我眼馋creator很久了 无奈没本事自己把cocos2d-js升级过去.

这个内存释放很好理解, jsb中存在c++内存释放 与 js内存释放, 而CC_ENABLE_GC_FOR_NATIVE_OBJECTS就是将两者关联起来 js释放掉后才会释放c++对象. 也就是说你只需要保证js对象能够被内存回收就可以了, 而不是一定要 this.sprite = null;

js内存回收机制有两种, 引用计数与标记清除, 在你上面 =号 就是引用计数.
标记清除自己百度,总之就是你只需要要保证从js的global根对象无法访问到对象就可以了,例:
this.a = new Sprite();
this.a.b = new Sprite();
this.a = null;
这时候并不需要this.a.b =null
更多细节 暂不讨论

OVER

http://forum.cocos.com/t/topic/53075 panda有空看下这个问题么

能顺便让libjs_static.a支持一下bitcode不

使用增量GC,尝试下这个
JS_SetGCParameter(_rt, JSGCParamKey::JSGC_MODE, JSGC_MODE_INCREMENTAL);
JS_SetGCParameter(_rt, JSGCParamKey::JSGC_SLICE_TIME_BUDGET, 50);

哥们,你移植jsb2.0到cocos2d-x 3.12上成功了吗?我现在也要考虑做这个事,前面终于啋过了cocos2d-x 3.13上的jsb的一些坑。

大佬 同遇到老版cocos2d-js spidermonkey计算远落后于lua,请问你的升级修改能做个教程吗,收费也可以

这个搞的有点年头了,可以加个 qq:453951749 ,然后细聊一下,看看你的需求