性能文章>腾讯MOO音乐关于Flutter的内存泄漏的排查实战(中)>

腾讯MOO音乐关于Flutter的内存泄漏的排查实战(中)转载

5月前
195401

导言

MOO 音乐是 TME 旗下的新锐音乐服务,其团队是公司内最早实践 Flutter 的先行者之一。本系列文章将提炼 MOO APP 开发中遇到的情况,就 Flutter 内存占用治理方面,分享日常开发的一些基本认知、注意要点、排查方法和优化方案。内存治理篇文章共分上、中、下三篇,本篇为中篇。

上篇已经介绍了关于Flutter的内存问题腾讯MOO音乐关于Flutter的内存治理(上),今天我们进入实战,来了解一下内存泄漏应该怎样解决!

 四、内存泄漏的排查实战

为了便于我们定位具体问题代码,Android Studio 或 VS Code 插件帮我们包装了相关内存工具,这些工具都基于 debug 模式下 Dart VM service 暴露的接口开发的,Dart VM service 自身也带有协助排查内存问题的工具 - Dart VM Observatory,attach 之后访问 service 提供的 http 链接即可使用该工具,内存排查功能路径为:Isolate (main)  --> Allocation Profile。

工具有了,如何排查定位导致内存泄漏的问题代码呢?

  • 对同一个功能或页面进行反复相同的进入、退出操作;
  • 然后执行强制 GC,查看不同操作后的内存快照;
  • 对比该功能关联的对象实例增加情况;
  • 如果强制 GC 后实例只增不减或该回收的对象没有被回收,没有特殊的延时处理一般就可以判断相关代码有问题。

下面以 Image 内存泄漏排查为例,展示具体的问题代码定位过程,目标是排查列表项内存泄漏,功能进出动作对应着列表项的滑窗动态创建和销毁。

1. 我们打开 APP 其中一个页面,如某个列表页,通过 Xcode 观察应用整体初始内存 470MB,如图所示。

腾讯MOO音乐关于Flutter的内存泄漏的排查实战(中)数据图表-heapdump性能社区

 

往下翻了几页,内存持续上涨,并且表现为一直翻页一直涨,这种情况大概可以确定页面存在内存泄漏问题,如图所示。

腾讯MOO音乐关于Flutter的内存泄漏的排查实战(中)数据图表-heapdump性能社区



2. 打开自带工具 Allocation Profile 界面后,点击右上角 GC 按钮,强制回收所有可回收对象,如图所示。

腾讯MOO音乐关于Flutter的内存泄漏的排查实战(中)数据图表-heapdump性能社区

回收了可回收对象后,剩余的便是当前 Isolate 状态下的内存快照,都是强引用内存对象。

3. 根据初始内存快照和当前快照的对比,可明显看到图片实例有明显的增长,并且随着不断翻页持续增长,更明显超过了图片缓存的大小的限制。

腾讯MOO音乐关于Flutter的内存泄漏的排查实战(中)数据图表-heapdump性能社区

腾讯MOO音乐关于Flutter的内存泄漏的排查实战(中)数据图表-heapdump性能社区

从这里我们可以确定 Image 对象实例存在引用没被释放的问题,下一步是找出 Image 引用的持有对象。

4. 点击 Image 链接,如图所示。

腾讯MOO音乐关于Flutter的内存泄漏的排查实战(中)数据图表-heapdump性能社区

进入新页面后找到 strongly reachable,展开可看到内存快照中具体的 Image 对象列表,如图七所示。

腾讯MOO音乐关于Flutter的内存泄漏的排查实战(中)数据图表-heapdump性能社区

5. 进入 Image 实例详情界面,如图八所示。

腾讯MOO音乐关于Flutter的内存泄漏的排查实战(中)数据图表-heapdump性能社区

6. 查找对象引用未释放的节点,通常要翻查外部对象引用链,从上图可以看出该 Image 实例最终被 _CacheImage 引用,是图片缓存正常持有的引用。

根据图片缓存的 LRU 机制,可以断定会存在图片缓存释放掉但被其他对象持有的 Image 实例对象,我们可以继续尝试别的 Image 实例排查其引用情况。

7. 经过随机翻查了一些 Image 实例,发现了一些线索,如图九所示。

腾讯MOO音乐关于Flutter的内存泄漏的排查实战(中)数据图表-heapdump性能社区

这个 Image 实例引用已经被 ImageCache 对象释放,但没有被正常回收。

8. 从引用链可以看出,DisplayDecorationImagePainter 对象是我们封装的类,ImageStreamListener 对象持有了相关引用,正是因为这个引用链导致了 Image 对象实例没被回收。

9.  翻查了一下代码,发现是由于 DisplayDecorationImagePainter 注销时没有给 ImageStream 反注册监听。

腾讯MOO音乐关于Flutter的内存泄漏的排查实战(中)数据图表-heapdump性能社区

10. 补充了反注册代码之后,重复前面的操作,持续滚动翻页,图片实例数量维持在 122MB 左右,内存也没有持续增长,如图十所示。

腾讯MOO音乐关于Flutter的内存泄漏的排查实战(中)数据图表-heapdump性能社区

到此,图片内存问题已经得到解决。

排查过程就是在对象实例的引用链上寻找代码线索的过程,针对图片泄漏的排查,可以设置一个较小的图片缓存阈值,减少图片对象缓存,干扰对象少了排查效率就大大更高。

排查泄漏是个频率较高的重复操作,通常排查特定功能都会关注特定的相关对象,自带的排查工具对关注的对象没有较好的过滤功能,而且操作路径长,引用链显示也不够直观。可以考虑自研排查工具来解决这个效率问题。

 

更多思考:

本次向大家介绍的是Flutter内存泄漏的优化方案,其实Flutter的各种优化都很多,大家可以通过阅读以下文章系统的学习Flutter!

Flutter混合栈路由实践与优化

美团FlutterWeb性能优化探索与实践

 

点赞收藏
michi
请先登录,感受更多精彩内容
快去登录吧,你将获得
  • 浏览更多精彩评论
  • 和开发者讨论交流,共同进步

为你推荐

从20s优化到500ms,我用了这三招

从20s优化到500ms,我用了这三招

为什么mysql的count()方法这么慢?

为什么mysql的count()方法这么慢?

聊聊ThreadLocal的八个关键知识点

聊聊ThreadLocal的八个关键知识点

Java 异步调用原理与实战

Java 异步调用原理与实战

每个 Java 工程师都必须知道的五个 API 性能优化技巧

每个 Java 工程师都必须知道的五个 API 性能优化技巧

【译】为什么我的数据库很慢,10 个查询反而比 1 个查询更快?

【译】为什么我的数据库很慢,10 个查询反而比 1 个查询更快?

1
0