记录<一个多SDK中引入ffmpeg出现的top1的crash问题>解决方案

一. 背景

App从某个版本开始突然收到一例高频crash,,crash信息如下

在这里插入图片描述
crash栈如下:
在这里插入图片描述

crash栈信息很少,只能看出是线程刚启动就crash了,内存违规访问,并且通过image可以知道是crash在我们自己的代码里,除了这几点信息很难找出其他线索了。

二. 分析、定位crash源代码

通过栈可以知道crash在frame_worker_thread函数里面,并且是c/c++函数,直接搜我们工程没找到该方法,所以应该是某个引入库的方法。
使用xcode搜索image symbol:

在这里插入图片描述

什么???竟然有两个同名的frame_worker_thread函数!!!两个同名的函数不会链接错误吗?其实frame_worker_thread是non-external symbol,所以链接没问题。
搜索symbol知道其中一个frame_worker_thread 方法在pthread_frame.c文件定义的,这个文件是FFmpeg库文件,由于我们App同时使用了SDK1和SDK2,所以会有两个frame_worker_thread方法。
知道frame_worker_thread是FFmpeg库文件后,还有个问题,通过crash栈并不知道是SDK1还是SDK2的sdk引起的crash,这个时候回头分析crash log后发现,crash栈附近线程栈都是SDK1的代码,所以基本就可以确定是SDK1的问题。
反馈给sdk的开发替换sdk后发现并没有解决问题,所以自己又尝试分析了一下。

三. 分析汇编

在这里插入图片描述

分析汇编可以知道是x20寄存器为0导致的crash,并且看汇编大概可以猜测是在读取对象的成员变量时crash的,x20应该是对象指针

四. 分析源码

FFmpeg是开源的,分析源码后可以确定crash的在下面位置:

在这里插入图片描述

可以看出是avctx指针为0导致的,接下来是要分析

  • avctx是怎么赋值的
  • avctx为什么会为0

首先分析avctx是怎么赋值的

在这里插入图片描述

可以看出在ff_frame_thread_init函数里线程创建前会为线程分配内存并赋值avctx,并且有判空处理,所以可以排除是线程创建时赋值错误的情况。
现在可以确定avctx是在赋值后变为0的存在两种情况

  • 内存破坏
  • 错误的释放了

如果是内存破坏的话问题就很难解决了,因为内存破坏导致crash的时机很随机,除非能复现,不然要找出内存破话的地方非常难,必需分析内存破坏后内存的内容,但crash log没有crash上下文。所以先从简单的情况分析,先分析内存释放场景,分析源码可以知道内存是在ff_frame_thread_free函数里面进行释放的。

在这里插入图片描述

在知道内存分配和释放的地方后进一步分析调用ff_frame_thread_initff_frame_thread_free的逻辑,用xcode在这两个函数打断点调试后发现调用ff_frame_thread_init后马上会调用ff_frame_thread_free,这个时候线程还没来的急创建,ff_frame_thread_free在线程创建前把内存释放了。
跟SDK1对接确定后,发现播放视频的时候会先调用ff_frame_thread_init创建一个软解线程,然后如果开了硬解后又立即调用ff_frame_thread_free释放相关资源,这个时候软解线程其实还没启动,所以在软解线程启动的时候内存已经释放了,SDK1对接修改这个逻辑后就再没出现这个crash了~

五. 思考

个人感觉FFmpeg这里释放内存不是很合理,如果让线程自己去释放内存就不回出现这个问题了。

猜你喜欢

转载自blog.csdn.net/weixin_45581597/article/details/127868767
今日推荐