当前位置:   article > 正文

【Bug】EGL内存泄漏导致Android系统无响应的问题_android graphics内存不释放

android graphics内存不释放

场景描述:

在自行压测检查的时候,发现到一个非常难排查的问题:
1.发起录制、 2.sleep(1000)、 3.结束录制
反复执行以上步骤,约五十次左右,app假死,导致整个机子无响应,只能关机重启设备


原因分析:

猜测1:大屏端的录屏和取消录屏,申请共享内存的时候冲突了?
表现上不像,比较像内存泄漏导致的。

猜测2:内存泄漏
用Profile分析了下Java部分,不是很多
初步-内存泄漏,但是不多
而且,Java内存泄漏,也不该爆系统

猜测3:native内存申请没释放,爆堆外内存了,不过这比较难使用Profile,因为要不了几次就爆系统了
使用Profile查看如下:Graphics内存陡增
问题逐渐明朗,这陡增骤死的Native和Graphics内存

接下来的难点就是怎么排查了,记录内存快照需要一定的时间,换个角度思考下,毕竟怀疑是内存泄漏,那在内存泄漏导致问题前record就行,将复现的代码改为反复执行35次左右。

理论上,应该可以通过代码上,多进程、预留fd、Flash占坑等措施+异常告警来抓取,但有点牛刀小试

Profile结果如下,结合场景分析,将范围缩小到EGL,但是因为无法跟踪到C++部分,而且可能Profile有些问题,上图的graphics也不是每次record都出现。
内存占用大小
走读EGL相关的关键代码,看下使用方式是否有误?

  • 释放顺序(x)
  • 其他地方引用?绝对不可能(x)

结合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()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

发散思考:

如何正向定位到这个问题?想法很简单,就是检测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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/303644
推荐阅读
相关标签
  

闽ICP备14008679号