赞
踩
在自行压测检查的时候,发现到一个非常难排查的问题:
1.发起录制、 2.sleep(1000)、 3.结束录制
反复执行以上步骤,约五十次左右,app假死,导致整个机子无响应,只能关机重启设备
猜测1:大屏端的录屏和取消录屏,申请共享内存的时候冲突了?
表现上不像,比较像内存泄漏导致的。
猜测2:内存泄漏
用Profile分析了下Java部分,不是很多
而且,Java内存泄漏,也不该爆系统
猜测3:native内存申请没释放,爆堆外内存了,不过这比较难使用Profile,因为要不了几次就爆系统了
使用Profile查看如下:
问题逐渐明朗,这陡增骤死的Native和Graphics内存
接下来的难点就是怎么排查了,记录内存快照需要一定的时间,换个角度思考下,毕竟怀疑是内存泄漏,那在内存泄漏导致问题前record就行,将复现的代码改为反复执行35次左右。
理论上,应该可以通过代码上,多进程、预留fd、Flash占坑等措施+异常告警来抓取,但有点牛刀小试
Profile结果如下,结合场景分析,将范围缩小到EGL,但是因为无法跟踪到C++部分,而且可能Profile有些问题,上图的graphics也不是每次record都出现。
走读EGL相关的关键代码,看下使用方式是否有误?
结合OpenGL ES:Android平台EGL环境,发现在release的时候没有进行释放。
在不需要EGL的使用,进行释放,典型的前人挖坑,后人吃土案例。
EGL14.eglMakeCurrent(mEGLDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT)
EGL14.eglDestroySurface(mEGLDisplay, mEGLSurface)
EGL14.eglDestroySurface(mEGLDisplay, mEGLSurfaceEncoder)
EGL14.eglDestroyContext(mEGLDisplay, mEGLContext)
EGL14.eglDestroyContext(mEGLDisplay, mEGLContextEncoder)
EGL14.eglTerminate(mEGLDisplay)
EGL14.eglReleaseThread()
如何正向定位到这个问题?想法很简单,就是检测C++的内存泄漏。有可用开源:LeakTracer
但无论是EGL还是OpenGL ES都是系统库,非debug版,且没有调试文件,看不了堆栈。不过倒是可以用来监听自身代码里的内存泄漏。
集成流程参考:使用LeakTracer检测android NDK C/C++代码中的memory leak
原理上是通过重载new/delete、new[]/delete[]、malloc/free,在分配时记录信息并调用系统的函数,释放时销毁记录并调用系统的释放函数,在trace结束时,遍历进行分析。
踩坑:dlsym设置为RTLD_DEFAULT(从0开始),在8.0设备上SOF,设置为RTLD_NEXT(从当前开始),5.0设备上Crash
分析:因为android加载libleaktracer.so的顺序碎片化,8.0上先load了lt_malloc,然后从0开始查找__libc_malloc,但libc.so在libleaktracer.so之后,又命中lt_malloc,所以出现了SOF;5.0则是libc.so在libleaktracer.so之前,若从当前查找__libc_malloc,根本找不到,触发crash。
解决:native判断android api版本(其实就是读个配置文件),选用合适的dlsym模式
int MemoryTrace::androidVersion() {
// 1. 获取 SDK 版本号 , 存储于 C 字符串 sdk_verison_str 中
char sdk[128] = "0";
// 2. 获取版本号方法
__system_property_get("ro.build.version.sdk", sdk);
//3. 将版本号转为 int 值
int sdk_version = atoi(sdk);
return sdk_version;
}
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。