使用工具DevEco Studio NEXT Developer Preview2定位过程分析crash日志,发现11048线程发送事件后,一直没有手动响应,如下:继续往下分析crash日志,发现该线程存在锁处理,并处于等待状态中,如下:根据这里的调用关系,分析CVHttpClient::DetachHttpEventObserver函数处理,发现该函数会通过锁来释放CVHttpClient类的成员变量资源,释放资源使用已经封装好的自定义remove函数。初步怀疑,应该是成员变量的remove函数里存在类的析构处理,使用到了锁,而该锁在其他调用时,没有释放,而remove里使用到的释放资源是已经稳定的公共类接口,经过了许多项目考验,不会存在问题。进一步分析得知,该成员变量是一个模板类的数组成员,那么,这里的模板使用的类是否存在异常处理。进入分析模板使用的类的实现,首先查看该类定义的成员变量,发现里面存在定义的成员存在CVHttpClient类,继续分析释放的处理,先看析构函数,此时,发现析构函数中,对CVHttpClient类使用了delete操作,这样就存在了锁的两次调用。这里不应该将资源释放调,应该将资源释放到已经写好的模块中管理起来,见下(注释是修改前的,修改后的是24\~27行):修改完毕后,为验证是否是这个原因引起的问题,在CVHttpClient::DetachHttpEventObserver函数,以及上面截图的析构函数中,增加打印,验证业务是否会同时运行进来,经验证,业务会同时进入,至此,问题解决。根因总结代码中,存在循环成员包含情况,在资源释放过程中,发生了死锁。解决方案已经封装了全局管理模块,释放的成员,直接放到管理模块的数据中,不需要释放作析构处理。
使用工具
DevEco Studio NEXT Developer Preview2
定位过程
分析crash日志,发现11048线程发送事件后,一直没有手动响应,如下:
继续往下分析crash日志,发现该线程存在锁处理,并处于等待状态中,如下:
根据这里的调用关系,分析CVHttpClient::DetachHttpEventObserver函数处理,发现该函数会通过锁来释放CVHttpClient类的成员变量资源,释放资源使用已经封装好的自定义remove函数。
初步怀疑,应该是成员变量的remove函数里存在类的析构处理,使用到了锁,而该锁在其他调用时,没有释放,而remove里使用到的释放资源是已经稳定的公共类接口,经过了许多项目考验,不会存在问题。
进一步分析得知,该成员变量是一个模板类的数组成员,那么,这里的模板使用的类是否存在异常处理。
进入分析模板使用的类的实现,首先查看该类定义的成员变量,发现里面存在定义的成员存在CVHttpClient类,继续分析释放的处理,先看析构函数,此时,发现析构函数中,对CVHttpClient类使用了delete操作,这样就存在了锁的两次调用。
这里不应该将资源释放调,应该将资源释放到已经写好的模块中管理起来,见下(注释是修改前的,修改后的是24\~27行):
修改完毕后,为验证是否是这个原因引起的问题,在CVHttpClient::DetachHttpEventObserver函数,以及上面截图的析构函数中,增加打印,验证业务是否会同时运行进来,经验证,业务会同时进入,至此,问题解决。
根因总结
代码中,存在循环成员包含情况,在资源释放过程中,发生了死锁。
解决方案
已经封装了全局管理模块,释放的成员,直接放到管理模块的数据中,不需要释放作析构处理。