2018-09-25

2018-09-26  本文已影响0人  前端林志文

BUG

loading时偶尔卡住bug

表现:无法继续,无报错,出现概率:2/10,所有平台都会重现,引入声音加载后更容易重现。

  1. 如何获取卡住的目标模块堆栈信息?卡住后程序实际还在运行,这时候打算加入断点,但目标模块已经不在运行,加入断点也无效,这时候加入的地方是一个系统Timer,当卡住后,在Timer的callback中打断点,游戏主程序会被断下来。

  2. 在Timer打断点,如何才能获取目标模块的内存信息?这时候可以预先在目标模块加入调试代码,例如window.__xxxModule = RES.instance; 将目标的的局部变量引用存到全局变量里面,这样断点的时候可以在watch窗口输入window.__xxxModule查看目标的内存信息。

  3. 查看window.__xxxModule模块后,发现没有声音模块的引用,无法获得声音模块的对象信息,重新修改引擎代码,将声音模块的引用加入到其父模块中,例如RES.instance.sound = sound; 注意新加的引用最好加入到其父模块,阅读大概的加载流程和父子模块的生命周期是否一致,子模块可以由父模块哪些变量管理。加完子引用后重新执行步骤1。

结论:发现加入引用后bug无法重现啊。经分析是白鹭的资源加载模块,没管理子加载模块的引用,导致浏览器在gc的时候被回收,callback无法回调结果卡住。

修复:声音模块引用有问题,需要确定其他加载模块是否也存在同样问题。经发现,图片加载模块也是有bug的,图片加载模块使用了缓存池,前4组线程一旦成功就会被缓存池引用,但万一刚加载就被gc掉了,也会导致卡住的问题。所以都要给父模块加入子模块的引用才行。

关闭某UI时,偶尔报错

表现:报错堆栈被中断,无法获取有效信息。在某些情况下,Timer或者Promise回调回来的堆栈不完整,无法获取所有堆栈内容。出现概率 2/50。

  1. 由于问题出现在关闭UI的瞬间,只要提升关闭次数,就能提高重现概率,编写测试代码,
while(1000) {
    UIMgr.open(xxx);
    UIMgr.close(xxx);
}

若以上代码不出错,考虑到偶现的都是定时器或者动画引起的,需加入延迟关闭的测试代码,

while(1000) {
    UIMgr.open(xxx);
    Timer.After(1000, UIMgr.close(xxx));
}

结论:经发现,是有子模块的对象没被释放,对象内的定时器还在运行,回调的对象已经无效。

修复:在onExit中加入对子模块的释放。

某动画移动的位置总是不对

表现:某一时刻出现很多飞金币飞资源动画,但只有飞金币动画位置不对,查看代码逻辑没发现问题。

游戏越来越卡

表现:刚进游戏流程,游戏后期很变卡和发热严重。

  1. 假设是最消耗内存的骨骼动画释放问题:在游戏登录界面,编写测试代码,增加两个button: add/sub, addBtn创建1000个骨骼动画, subBtn删除1000个骨骼动画,重复操作几次,若是界面骨骼动画数量为0时,内存和cpu都没法下降,必然是骨骼动画释放机制有错,导致内存泄漏。若是UI问题,操作方式也差不多。

UI关闭时骨骼动画释放偶尔报错

表现:偶尔会出现调用到无效骨骼对象的报错堆栈信息

  1. 给每一个arm对象增加唯一标志: this.name = Math.random();clock.add(arm)的前一句代码中加入 console.log("add:" + this.name); close.remove(arm)前一句代码中加入 console.log("remove:" + this.name); 通过输出log,观察每个对象创建是否都已经被释放。用眼睛看log比较累,其实可以通过写测试模块,封装好关键信息,定时收集,不匹配就输出断言,这样就不需要用眼睛对比log信息。

  2. 经发现,前两次的UI创建和释放log交错输出,统计发现总是差一次释放。

结论:是由于关键的add,remove代码不同步导致的,主要原因是创建骨骼动画是异步回调的。例如:

UIxxx {
    onEnter() {
        let cb = (arm)=> {
            clock.add(arm)
            this.arm = arm;
        }
        createArm(cb)
    }

    onExit() {
        if (this.arm) {
            clock.remove(this.arm);
            this.arm = null
        }
    }
}

修复:关键的add,remove尽量不要引入其他条件判断(谨慎)。进出的逻辑操作一定要尽量贴近对象的创建和释放代码。

某IOS版本上,拖放对象时出现黑块

表现:只在特定IOS版本上才能重现

  1. 初步怀疑是UI中的某些节点干扰,采用排除法,先将无关的节点隐藏。发现还是能重现。

  2. UI没找到问题,接着采用代码屏蔽法,先将拖动的代码注释掉,发现表现正确了。初步确定问题所在。

  3. 逐步注释代码,最后将hitTest(true);修改为hitTest();发现表现正确,而且操作逻辑无误。

结论:使用了特定ios版本不支持的像素检查属性,预估是白鹭的bug.

修复:修改为hitTest()就行了,正常逻辑本来就不需要采用像素检查。

IPHONE SE 二维码无法生成

表现:只在特定iphone se上才能重现

  1. 查看系统Image加载dataURL的代码,经发现是加载dataURL时WebImage发生错误,但没有输出具体错误信息。

  2. WebImage代码不多,只有十几行,采用代码注释排除法。最后将Image.crossOrigin注释掉。发现二维码能生成了。

结论:iphone_se不支持匿名跨域创建Image DataURL。

修复:在Image loader里面,判断当前src是否dataURL,若是临时关闭跨域属性。

IPHONE X 游戏模糊

表现:经发现,不仅仅是IPHONE X,只要在特定的宽高比就会变得模糊

  1. 怀疑白鹭改出bug了

  2. 下载白鹭github上面的工程。

  3. 采用git log -S 命令刷选 模糊 关键字。查看修改的代码,尝试还原测试。

结论:发现有一次代码提交,是修正字体模糊,针对canvas所加的。

if (egret.Capabilities.renderMode == "canvas") {
    canvasScaleX = Math.ceil(canvasScaleX);
    canvasScaleY = Math.ceil(canvasScaleY);
}

修复:发现将针对canvas的条件后注释,模糊问题基本解决;

总结

  1. 创建测试环境
  2. 创建必现条件
  3. 编写测试代码
  4. 注释代码(参考二分查找算法)
  5. 查找历史记录log
上一篇下一篇

猜你喜欢

热点阅读