内容简介:苍翼之刃:论File Descriptor泄漏如何导致Crash?
本文来自于腾讯 Bugly,是由 Bugly 邀请腾讯内部各位技术大咖,通过日常工作经验的总结以及感悟撰写而成,内容均属原创,非经作者同意,请勿转载。
这一期的团队分享,我们特邀苍翼之刃的开发负责人Jay,为大家分享在Android项目中遇到的一些Crash。
苍翼之刃外文:BlazBlue Revolution Reburning,是由Arc Systerm Works 正式授权,并由 91Act 负责研发的横板动作手游,森利道全程监修,也是苍翼默示录系列唯一的一部横板动作手游。 游戏内部代号为:BBRR,全称是BLAZBLUE Revlution Reburning,续BBCT、BBCS、BBCS2、BBEX、BBCP 之后的又一力作。
背景
在 nix系统中,许多的资源都会被定义为File Descriptor(下面简称FD),例如普通文件、socket、std in/out/error等等。每个 nix系统中,单个进程可以使用的FD数量是有上限的。不同的*nix系统中,这个上限各有区别,例如在Android里面这个上限被限制为1024。
案例分析
在实际的Android开发过程中,我们遇到了一些奇奇怪怪的Crash,通过sigaction再配合libcorkscrew以及一些第三方的Crash Reporter都捕获不到发生Crash的具体信息,十分头疼。 然后我们通过Bugly上报的 Java 的CallStack观察发现这些Crash发现了一些共同的信息:
看来是和OpenGL有关系,于是我们进一步对程序输出的log进行观察,又发现:
从这个log里面我们获得了几个信息:
- 几乎所有出现这种Crash的设备,都是Adreno的GPU
- 几乎所有Crash都会伴随着requestBuffer failed
我们对我们已有的设备反复试验,确实了只有Adreno的设备(小米3,HTC M8,华为P7等)会在特定条件下出现这种奇奇怪怪的随机Crash。而其他设备例如小米Pad(Tegra),三星S3(Mali)等都不会出现这种问题。
这个问题确实头疼,在网上搜索了很久也没找到有用的信息。直到在某次小米3上再次测试的时候,发现了log里面还有一条必然出现的信息:
这个信息间接的指出了问题,也给了我们一些提示:似乎打开了过多的文件。于是靠着这个灵光,我们尝试着在程序中输出所有已打开的文件:
通过不停测试程序,发现已打开的文件数量一直有增无减,而当这些被打开的文件数量接近1024的时候,上面的eglSwapBuffers必然出错。于是乎我们得出一个中间结论:
- 如果程序打开的文件数量过多,会导致OpenGL swap buffer失败!
这从字面上看着似乎有些扯淡,因为这两者总感觉没啥联系。这个问题只会出现在Adreno的GPU上面,于是我们猜想:
- Adreno的驱动在swap buffer的时候,需要申请新的FD,这个FD可能是某些硬件IO,具体不得而知;
- 如果程序中其他的各种FD使用过多接近上限,会导致Adreno的驱动申请不到必要的FD,因此导致swap buffer失败。
这样看起来似乎就比较有道理了。虽然sawp buffer本身是不会Crash的,他并没有raise任何signal,只是简单的返回了一个错误的结果,但这会导致上层逻辑出现异常。这些异常在不同的设备上表现不一样:
- 有的设备会在Java层的eglSwapBuffers触发Java层的Exception导致Crash;
- 有的设备不会出现异常,但是会导致OpenGL停止工作(halt rendering),其表现结果就是程序卡住无响应;
- 有的设备可能什么都不会发生,但是如果你的交互触发了其他逻辑:比如按回退键弹出对话框,对话框也需要FD,但是获得不到,那么弹出对话框的逻辑将抛出异常。 于是这就有了各种奇奇怪怪的Crash。
解决方案
通过对代码的排查,我们发现在使用SoundPool处理音效的时候,确实存在FD泄露的情况:
虽然我们在不需要这些音效的时候,对其进行了卸载处理,但不知道是SoundPool类自身的缺陷,还是我们的使用不当,在实际测试中我们发现unload过后,在load中通过openFd打开的FD并没有被释放掉。 强制调用System.gc()在一些设备(例如小米3)上可以释放掉这部分FD,但是另一些设备(例如HTC M8)即使强制gc这无法卸载掉它们,于是便出现了FD泄露的情况。 最终我们自行对这些FD进行管理,并且在unload的时候手动调用这些FD的close方法:
这之后FD再无泄露的情况发生,之前的各种设备上面的各种奇奇怪怪的Crash都被处理好了。
小结
这个问题粗略说起来就是:因为播放了太多的音效,导致Adreno底层渲染失败,以至于上层逻辑各种失措,产生了很多奇奇怪怪的Crash。 准确的解释应该是:程序中的FD泄露如同内存泄露一样是同样需要得到关注的问题,FD的耗尽如同内存的耗尽一样会导致程序的各种异常情况发生,但是前者不如后者那么知名也不如后者容易被察觉。
如果你觉得内容意犹未尽,如果你想了解更多相关信息,请扫描以下二维码,关注我们的公众账号,可以获取更多技术类干货,还有精彩活动与你分享~
腾讯 Bugly是一款专为移动开发者打造的质量监控工具,帮助开发者快速,便捷的定位线上应用崩溃的情况以及解决方案。智能合并功能帮助开发同学把每天上报的数千条 Crash 根据根因合并分类,每日日报会列出影响用户数最多的崩溃,精准定位功能帮助开发同学定位到出问题的代码行,实时上报可以在发布后快速的了解应用的质量情况,适配最新的 iOS, Android 官方操作系统,鹅厂的工程师都在使用,快来加入我们吧!
以上所述就是小编给大家介绍的《苍翼之刃:论File Descriptor泄漏如何导致Crash?》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- Hadoop 不需认证导致数据泄漏
- 记一次Font导致JVM堆外内存泄漏分析
- 一文带你了解如何排查内存泄漏导致的页面卡顿现象
- 每日一道面试题(第三期)---一般什么情况下会导致内存泄漏问题
- 我的程序跑了60多小时,就是为了让你看一眼JDK的BUG导致的内存泄漏。
- Android 系统开发_内存泄漏篇 -- "内存泄漏"的前世今生
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。