宕机BUG:Cocos Creator 1.6宕机

安卓连出四次闪退问题汇总.这些推栈根本很难看出哪里的问题,反正就是出现了野指针.

大概看了一下CCNode.js的代码,这里的问题主要是_sgNode,我想这个_sgNode代表不同的平台不同实现,这里在JSB环境下,应该是C++中的Node,如果这样理解没错,js中的cc.Node如果被引用,但_sgNode被销毁了,js中的cc.Node并没有销毁,这里_sgNode就变成了野指针,如果要临时解决,在所有使用_sgNode之前都用cc.isObjectValid()先判断是不是已经销毁,如果销毁了就返回.如果在C++层可以判断也是一样的.因为这个BUG是偶现的,如果这样只要不闪退,用户层就是无感知的,而且这种BUG我估计很难查.

当你一筹莫展,无从下手的情况下,加个参数效验就能解决问题.:grin:

还有一个思路,我看了CCNode.js在_onPreDestroy的时候有把_sgNode=null,这里出现了野指针应该是C++代码里多调用了release.另一个思路就是C++代码里真正delete时发一个事件,通知js这边,js得到事件以后把_sgNode=null,这样出现错误只会报一个脚本错误,而不会闪退,当然前提是你这个错误错误不出现在start onDisable等里面(这里面会死循环).所以我建议先用这个思路解决问题,这样要修改的代码不多,实现起来很容易,解决问题很彻底.

这个是在 spriteFrame.getTexture() 调用的时候崩溃,创建或者获取 texture 的 js 对象时失败。

检查 sgNode.isRunning() 的时候崩溃

sgNode.getParent() 崩溃

在 touchend 事件中调用 label.setString() 崩溃

不过从 binary 的调用栈中确实还缺失很多信息,如果你这边不愿意用 default 或者 link + Android Studio 的话,还麻烦给我们发一个 demo,这样我们可以自己重现并解决。因为这些问题跟游戏逻辑的关联性很大,有一些情况可能是我们没有预料到的

安卓的default我们都配置好了,就是编译不过,苹果发了default版但bugly抓不到闪退信息,回退了,下周再试一试。

会不会是用 default 版不闪退?:joy:

不是,半天闪了两次。

0 mimipoker-mobile js_cocos2dx_Node_setVisible(JSContext*, unsigned int, JS::Value*) + 132
1 mimipoker-mobile js_cocos2dx_Node_setVisible(JSContext*, unsigned int, JS::Value*) + 128
2 mimipoker-mobile js::InternalCallOrConstruct(JSContext*, JS::CallArgs const&, js::MaybeConstruct) + 304
3 mimipoker-mobile ScriptingCore::handleTouchEvent(void*, cocos2d::EventTouch::EventCode, cocos2d::Touch*, cocos2d::Event*, JS::MutableHandleJS::Value) + 676
4 mimipoker-mobile ScriptingCore::handleTouchEvent(void*, cocos2d::EventTouch::EventCode, cocos2d::Touch*, cocos2d::Event*) + 72
5 mimipoker-mobile std::__1::function<void (cocos2d::Touch*, cocos2d::Event*)>::operator()(cocos2d::Touch*, cocos2d::Event*) const + 44
6 mimipoker-mobile _ZNSt3__110__function6__funcIZN7cocos2d15EventDispatcher18dispatchTouchEventEPNS2_10EventTouchEE3$3NS_9allocatorIS6_EEFbPNS2_13EventListenerEEEclEOSA + 300
7 mimipoker-mobile std::__1::function<bool (cocos2d::EventListener*)>::operator()(cocos2d::EventListener*) const + 40
8 mimipoker-mobile cocos2d::EventDispatcher::dispatchEventToListeners(cocos2d::EventDispatcher::EventListenerVector*, std::__1::function<bool (cocos2d::EventListener*)> const&) + 216
9 mimipoker-mobile cocos2d::EventDispatcher::dispatchTouchEvent(cocos2d::EventTouch*) + 364
10 mimipoker-mobile cocos2d::EventDispatcher::dispatchEvent(cocos2d::Event*) + 208
11 mimipoker-mobile cocos2d::GLView::handleTouchesOfEndOrCancel(cocos2d::EventTouch::EventCode, int, long*, float*, float*) + 388
12 mimipoker-mobile -[CCEAGLView touchesEnded:withEvent:] + 500
13 UIKit -[UIWindow _sendTouchesForEvent:] + 2480
14 UIKit -[UIWindow sendEvent:] + 3192
15 UIKit -[UIApplication sendEvent:] + 340
16 UIKit ___dispatchPreprocessedEventFromEventQueue + 2400
17 UIKit ___handleEventQueue + 4268
18 UIKit ___handleHIDEventFetcherDrain + 148
19 CoreFoundation _CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION + 24
20 CoreFoundation ___CFRunLoopDoSources0 + 540
21 CoreFoundation ___CFRunLoopRun + 744
22 CoreFoundation CFRunLoopRunSpecific + 424
23 GraphicsServices GSEventRunModal + 100
24 UIKit UIApplicationMain + 208
25 mimipoker-mobile main + 108
26 libdyld.dylib _start + 4

苹果闪退又来了,换了个位置.这两天只出现了这一次.刚又现现了一次,两次了.
这个闪退可能跟我的这个代码有关,就是可能这个对象已经destroy了,但是cc.find还能找到.

安卓宕机又出现了新位置.一次给你报五条.

我开始怀疑另一个地方,就是onDestroy时,其实对象已经销毁,这跟C++的实现不一样,C++的release以后,只会在下一帧去销毁对象,在原理上保证了一定的安全性.但在js层,完全没有了这样一层优雅的保护,我怀疑是不是destroy以后还去调用了这个对象的API导致的宕机.其实也建议类似C++层的设计在destroy时不销毁对象,因为在destroy以后可能有些代码还在引用这个对象,而在下一帧去销毁,可以达到保护的目的,这也是C++层优良的设计之一.

先只看你这个show函数,似乎存在着一些问题。
cc.find("UI" + name)查找UI结点,只会在Scene一级查找结点,如果UI结点是Scene的孙子结点是查不到的(可以看API文档或自己测试)。而看你的参数有一个parent,也就是UI是可以作为其他结点的子结点的。这就可能会在场景中出现多个相同UI结点的情况。

这样重现这个问题:

  1. 先调用show函数:show(Bag, null, UIRoot),UIRoot是UI结点的父结点。调用完之后,创建出一个UIBag结点,并且加到UIRoot中。
  2. 过一会,你再一次调用show(Bag, null, UIRoot),这时就有问题了,因为cc.find找不到UIBag,导致cc.loader.loadRes再一次被调用,创建出了另一个UIBag,此时,UIRoot下面就有两个UIBag了。

退一步讲,如果你确保parent是scene,也有可能会出问题的,因为cc.loader.loadRes是异步的,你调了show之后并不会马上创建UIBag,如果在创建出来之前,你又一次调用了show函数(比如快速的点两下按钮),此时还是会有两个UIBag的情况。

另外代码中cc.loader.loadRes中的err这个参数没有处理,当然如果你确信不会加载不成功也可以的,只是从严谨的角度(也才符合你的风格吗:)),判断一下再主动抛错误,就可以在错误中加上更多有用的信息,也利于后面的除错。
还有一个zIndex似乎没有用到

上面可能与崩溃无关,只是从代码的逻辑上看有些问题,也有可能是因为这些问题暴露出引擎的键壮性不够。

创建出两次是可能的,但不会导致宕机,没有处理err,这里加载失败也不会宕机,都试过的.宕机根本这不是这逻辑的问题.zIndex根本无意义,这是之前本来打算用这个,后来没用就没管了.重点都不在这,逻辑写多了有些垃圾代码残留也很正常.不删除有时可能还要补回来,所以留着.

嗯,我只是看了你这个函数的一些问题,也是值得修改的。
崩溃这些还得再努力查了:)

不过我觉得你指出的是问题,是我们犯的错,应该改,有错就要承认改正.:grin:

你们的项目很成熟了吗?如果方便的话,能不能给我一下你们的项目测试看看,可以加我 QQ,100362595.

因为你这里出现了过多位置不固定的崩溃现象,我觉得很奇怪,如果是由哪些地方这么不稳定的话,理论上我们或者其他项目应该也可以普遍测试出来的,这些问题我们如果重现不了都没有办法修复,看 log 得到的信息太有限了

另外,我想问一下,是不是这些是项目上线之后收集到的崩溃现象?还是你们测试自己测出来的?大概崩溃比例是什么样?

Android的闪退是bugly上报的,苹果闪退是我自己使用中碰到的发生频率大概一天一次,有时一天都没有,有时一天两三次.我早加过你的QQ了,我只是换了个马甲:grin:,.安卓的闪退不是我亲测,我也不知道发生频率怎么样.

你的 destroy 一般是怎么写的?

onButtonBG: function () {
this.node.destroy();
},

基本都是这样写的

其实在切换场景的时候会自动 destroy 旧场景中的所有元素,你现在的操作在节点还有效的情况下做 destroy 可能有一些风险,我会尝试一下你这种方式,可能能重现问题,不过正常的流程应该是

this.node.destroy();