微信长时间不操作后点击会卡很久

1.任意一个手机设备,晾着游戏3分钟不去点屏幕【微信版本开启屏幕常亮】,次数点击一下屏幕,无论点哪个有button 都卡到爆炸,这个问题比较严重,我们游戏已经更新到了2.0.9,我们用户量很大,希望能尽快解决~~我们也在反复测试原因

2.其他问题后续再回复,第一条bug有点伤,我们先抓紧测试

@jare

可能要看下点击的回调里做了什么处理,有没有什么报错信息呢

在微信开发工具和手机上没有看到报错

但是有看到一坨微信的警告日志 类似于【‘requestAnimationFrame’ handler took 101ms 】
回调并没有做特殊处理:是这样的,只要点击屏幕任何一个按钮,都会出现巨大卡顿【和多久没点屏幕有关系,如果1分钟没点过,可能只是有一点点卡顿 如果10分钟没点,至少卡个4,5S 甚至过一会直接闪退】

我们最新的版本 没有做任何修改,只是升级了引擎,因为我们很多华为手机用户反应很卡顿,微信官方给我们的建议是升级到creator最新版,我们充分测试后发布,发布后发现很多用户反馈这个问题,我们自己也是100%必现

PS 我们是从2.0.8 升级到 2.0.9p1

看起来像是单帧占用了 101 ms 引起的,具体原因不好确定
方便提供下可复现问题的 demo 吗,我们这边好排查下问题

怎么看都不像是引擎的问题…… 感觉是某个缓冲区要用户输入时才会释放,问题是我们引擎里没有这样的机制。 应该没有点击 button,直接点击任意空白处也会卡吧?

论发帖标题的重要性, 一个bug汇总引来众多大佬回复。

光说升级版本导致的问题, 不如测试下具体调用了哪个方法调用耗时。

抱歉之前有点着急,我们先好生测试一番 有结果了再来回复你们 辛苦~~

抱歉标题起的不妥当,当时确实是想着把这两天收集到的问题统一反馈 但是突然有大量用户反馈,我们只能先专注这个问题了

另外我们当然也在测试呀,只是MAC微信工具性能比较好,有点难Hook这个点,当然也正在测试ing

测试结果出来了,看上面第二个图 这个函数花费了653.9ms的时间

1赞

我大概晓得原因了,因为我们游戏会产生大量的可点击物体,我看了一下源码:

_setDirtyForNode: function (node) {
    // Mark the node dirty only when there is an event listener associated with it.
    if (this._nodeListenersMap[node._id] !== undefined) {
        this._dirtyNodes.push(node);

这个函数会将加入监听的节点做一个标记 并且放入this._dirtyNodes

但是这个this._dirtyNodes 里的操作是在touch的时候,才会遍历操作,并且清空,那么如果一段时间不点击屏幕,会造成这里的节点越来越多,于是造成卡顿

而且这里有两重循环,暂时没完全理清这块逻辑,不知道应该怎么优化

1赞

等5,6分钟的话卡顿就更明显,不过加入监听的节点也并没有非常多啊,顶多100,150个,所以不是很理解这个性能消耗为何如此巨大

这块我们会排查一下,感谢反馈。另外请问下这个问题是 2.0.9 新增的吗?方便提供一个 demo 吗?

嗯,我们正在努力做一个空项目能复现的demo 现在看来需要一些条件组合才会出现这个问题

哈喽,有 demo 了吗

抱歉来晚了,之前版本比较急,做demo时发现仅仅是生成大量带 touch linstener的节点无法复现卡顿的情况,于是临时去掉了屏幕常亮功能来降低这个bug的发生率,中间项目事情比较多这个问题就暂时搁置下来,但是还是会有不少人遇到这个问题。

今天晚上终于闲下来,感觉复现太瞎子摸象,于是仔细分析源码后得到了结论,进而问题得到了解决

这个问题发生的原因是node 改变zIndex 时 会调用_onSiblingIndexChanged, 继而把该节点的所有兄弟节点做污染标记
_onSiblingIndexChanged () {
// update rendering scene graph, sort them by arrivalOrder
var parent = this._parent;
var siblings = parent._children;
var i = 0, len = siblings.length, sibling;
for (; i < len; i++) {
sibling = siblings[i];
sibling._updateOrderOfArrival();
eventManager._setDirtyForNode(sibling);
}
parent._delaySort();
},

问题在于 CCEventManager 的 _setDirtyForNode 方法 :
if (this._nodeListenersMap[node._id] !== undefined) {
this._dirtyNodes.push(node);
}
会把所有带监听事件的节点都加入_dirtyNodes ,而没有考虑重复问题,那么当场景里有比较多事件监听节点,并且他们不断发生zIndex变化时,可怕的事情就发生了,_dirtyNodes会被无限膨胀

于是在用户点击时 _updateDirtyFlagForSceneGraph 里会去遍历_dirtyNodes,因而引发了性能瓶颈。

我解决的办法是加入一个_dirtyNodeMap 相同node._id的节点只入数组一次,从而解决了这个问题

经过多次测试,发现问题已经得到了解决

2赞

附上修改后的源码 所有 _dirtyNodeMap相关的部分是为了修复这个问题而新增的代码
CCEventManager.js.zip (9.6 KB)

PS: 这个bug其实不仅会引发卡顿 还容易造成内存紧张,因为我们的游戏角色会经常移动,导致zIndex几乎每帧都会改变

1赞

确实有这个问题我也是2.0.9SP1,熄屏后再点亮,游戏就卡住了,过一会就正常了。