20230428----Android5.0-----解决句柄引起的内存溢出问题OOM

一、描述

产品是行车记录仪,基于Android5.0 开发的一个APP,将摄像头的预览界面数据编码后上传到网页平台,达到实现监控的一个功能。

二、问题

测试中,不断重复 网页平台请求视频,看到视频后,又关闭的一个压力测试,发现几十次操作以后,APP崩溃。

三、分析

抓了几份log,看到崩溃的地方是预览界面出错引起的,log如下:

D/MtkOmxVenc(  254): [0xf2717800] cc dst: w=1280, h=720, s=1280, uvs=640, f=0x3140868, sec=0

E/libEGL  ( 4769): eglMakeCurrent:782 error 300b (EGL_BAD_NATIVE_WINDOW)

D/AndroidRuntime( 4769): Shutting down VM

E/AndroidRuntime( 4769): FATAL EXCEPTION: main

E/AndroidRuntime( 4769): Process: com.example.mycarrecord, PID: 4769

E/AndroidRuntime( 4769): java.lang.RuntimeException: eglMakeCurrent failed

E/AndroidRuntime( 4769): 	at media.sdk.MediaSurfaceSdk.Opengles.grafika.EglCore.makeCurrent(EglCore.java:279)

E/AndroidRuntime( 4769): 	at media.sdk.MediaSurfaceSdk.Opengles.grafika.EglSurfaceBase.makeCurrent(EglSurfaceBase.java:119)

E/AndroidRuntime( 4769): 	at media.sdk.MediaSurfaceSdk.Opengles.KWindowSurfaceDrawer.onFrameAvailable(KWindowSurfaceDrawer.java:134)

E/AndroidRuntime( 4769): 	at android.graphics.SurfaceTexture$1.handleMessage(SurfaceTexture.java:203)

E/AndroidRuntime( 4769): 	at android.os.Handler.dispatchMessage(Handler.java:111)

E/AndroidRuntime( 4769): 	at android.os.Looper.loop(Looper.java:194)

E/AndroidRuntime( 4769): 	at android.app.ActivityThread.main(ActivityThread.java:5643)

E/AndroidRuntime( 4769): 	at java.lang.reflect.Method.invoke(Native Method)

E/AndroidRuntime( 4769): 	at java.lang.reflect.Method.invoke(Method.java:372)

E/AndroidRuntime( 4769): 	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:982)

E/AndroidRuntime( 4769): 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:777)

V/SettingsInterface(  758):  from settings cache , name = dropbox:system_app_crash , value = null

很明显报了 opengles 出错。一开始还怀疑是渲染出了问题,但是想想不对啊,opengles是源码,而且发现只有上传的时候才会崩溃,如果设备不上传数据到网页平台,只进行本地编码,放在那一直运行个两周都没出现崩溃问题,

于是把问题定位到网络上传那块。

顺便多看了一下崩溃之前的log,看看能不能有什么明显的地方导致渲染出错,从而引起APP崩溃。 于是发现了如下关键的地方:


E/Fence   ( 4769): merge: sync_merge("unnamed-4769-1:1", 993, 1018) returned an error: Too many open files (-24)

E/Parcel  ( 4769): writeDupFileDescriptor: error 24 dup fd 1020

E/Parcel  (  254): dup() failed in Parcel::read, i is 0, fds[i] is -1, fd_count is 1, error: Bad file number

E/BufferQueueProducer(  254): [GraphicBufferSource](this:0xf5852000,id:4,api:1,p:4769,c:254) queueBuffer: fence is NULL

W/hwcomposer(  227): [JOB] (0) Timed out waiting for vsync...

E/Surface ( 4769): queueBuffer: error queuing buffer to SurfaceTexture, -22

D/Grafika ( 4769): WARNING: swapBuffers() failed

D/flashlight_drv.cpp(  254): isOn()

把这部分可疑的log全都在CSDN中搜一下,发现这是一个文件句柄的错误。

调试

按照网上的办法,adb shell 进去 cd /proc/pid/fd 下边监控文件句柄情况。
在这里插入图片描述

按照网上说法是当这个文件句柄超过1024就会引起APP内存溢出崩溃。
然后进行一次网页视频请求,发现文件句柄就多了一些pipe啥的,然后关闭,又请求,多操作几次过来。
果然发现了文件句柄一直在不停的增多。比如时间为 05 分钟的时候请求一次,生成一些 pipe,关闭然后10分钟的时候又请求,又生成一些 pipe,那如果这样下来多操作几十次,肯定会超过1024崩溃的。
按照正常的逻辑是,05分钟请求视频生成pipe后,关闭视频以后应该会释放,但是并没有释放,05分生成的pipe一直在那里,10分生成的pipe也会一直在那里。

知道这关键的线索以后,就定位代码,到底是哪些代码导致一直在增加pipe的。
因为前面的测试发现是上传引起的崩溃,就去查看了一下上传的代码,代码的大概流程如下:
1、APP收到视频请求的指令。
2、APP连接服务器
3、APP打包编码的数据
4、APP将打包的数据上传

感觉是打包编码数据引起的,因为觉得这块可能耗内存,就暂时把 连接服务器的功能注释掉,注释掉下边的connect函数。
在这里插入图片描述

再adb进去查看文件句柄,测试发现网页请求视频的时候,文件句柄竟然不会增加pipe了。
所以问题的原因不是编码打包数据,而是在这一服务器连接connect函数上。

改正

这个连接是用了当今流行的网络框架netty。
想想有点不对。因为这个connect函数每次连接都要先配置一下什么参数啥的,如下:

在这里插入图片描述
这样想想不对啊,因为按道理说这些参数应该是初始化的时候配置过一次就OK了,不用每次都配置吧,会不会是每次配置增加pipe,而且又不释放掉呢。
于是做出了如下修改后:

结果给了我很大一个惊喜。
重新测试个200多次都APP都没崩。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值