一、背景
测试人员发现一个问题,就是反复快速进入详情页就会导致详情页崩溃,或者是app图标全部不可见。
二、解决过程
首先初步判断肯定是有性能问题,要么是内存太大,要么是内存泄漏了。
1.我们通过devTools查看彩页内存
a、点击Menory。b、多次反复进入退出页面。c、点击GC主动挥手回收对象。d、筛选我们的页面
发现存在多个页面对象。肯定是内存泄漏了
2.初步解决一些常见的内存泄漏问题
a、图片占用内存过大有可能导致内存泄漏,对图片做了一系列优化,防止内存过大;以及把图片相关需要释放的都在页面关闭时释放掉。
b、把页面里面其他需要释放的一些对象,全部释放掉了,减少部分内存泄漏。
经过测试,之前几次就会导致页面内存爆炸,现在需要三十多次才会导致内存爆炸。
3.还有其他内存泄漏源,继续查找
初步怀疑是getx框架有问题,所以在尝试getx哪里有问题。发现getx中的_routesKey会直接会导致页面不会被释放掉,加了如下一行代码,可以释放掉页面。
修改后,有的是可以释放掉页面,有的仍然无法释放。
所以getx确实会导致页面无法释放,导致内存泄漏,但是代码里面也还存在内存泄漏。
4.继续查找页面里面内存泄漏
由于页面中组件有几十个,设计的面积比较广,所以很难直接定位到。于是进一和我继续通过devtools查看内存以及对比内存差异,期望找到突破点。但是内存里面的对象有上百个,很难定位到底是哪一个,起初还误以为是attr和loader,因为他们泄漏很多对象。但是实际很难说是他们泄漏导致页面泄漏,还是页面泄漏导致这些对象泄漏。
最后我开始分析页面返回的数据,决定一个卡片去试,通过devtools分析可以判断出是哪一个卡片泄漏,找到卡片泄漏后,再一个组件去试,找到Image组件导致内存泄漏,最后再通过局部注释代码,最终定位到PreviewPptInheritWidget
class _PImageWidgetState extends State<PImageWidget> {
ui.Image? _rawImageContent;
ClipClipper? _oldClipper;
double? themeRadius;
PreviewPptInheritWidget? _previewPptInheritWidget;
...
@override
void initState() {
_previewPptInheritWidget = PreviewPptInheritWidget.ofUnDepend(context);
super.initState();
}
...
}
PreviewPptInheritWidget就是一个InheritedWidget子类,所以他是PImageWidge的父类。在PImageWidge持有PreviewPptInheritWidget对象,就会导致循环引用,最终导致内存泄漏。
所以大家后续如果使用InheritedWidget系列组件,最好不要持有(成员变量),如果非要持有,就需要在dispose的时候把InheritedWidget系列对象置空。
ios的同学可能非常熟悉循环引用,android同学之前几乎遇不到循环引用,android的同学可能要特别注意。
----------------------后续补充-------------------
后续又发现采用navigator.pop()退出页面不会出现内存泄漏。
如果是使用navigator.removeRoute()退出后台的某个页面,只会关闭页面,但是页面会出现内存泄漏。
大概是pop会去回收页面等完整流程,removeRoute只是移除路由。
有对这个十分了解的同学,也可以评论区交流