定位Flutter内存问题很难么?( 二 )



定位Flutter内存问题很难么?

文章插图
定位Flutter内存问题很难么?

文章插图
这里有一点需要注意,Observatory显示的Dart VM占用的内存信息要远远小于Android Profile/Xcode检测出的内存大小,因为存在部分只有系统工具能检测出的内存区块,例如一些完全不依赖于DartVM的skia对象,并且layer在engine中创建时并不能明确知道大小,所以采用虚拟近似值代替 。
 
  1. //engine/lib/ui/painting/engine_layer.cc
  2. ...
  3. size_tEngineLayer::GetAllocationSize {
  4. // Provide an approximation of the total memory impact of this object to the
  5. // Dart GC. The ContainerLayer may hold references to a tree of other layers,
  6. // which in turn may contain Skia objects.
  7. return3000;
  8. };
下面我们总结了几种常见内存泄漏的场景,在Java中都可以一一对应找到类似的场景,大家在业务开发中注意避免 。
 
常见内存问题
  • 未取消注册或回调导致内存泄露
示例代码:
 
  1. classDownloadManagerextendsObject{
  2. ......
  3. abstractclassDownloadListener{
  4. void completed(DXTemplateItem item);
  5. void failed(DXTemplateItem item, String errorInfo);
  6. }
  7. staticList<DownloadListener> listenerList = List;
  8. staticvoid downloadSingleTemplate(DXTemplateItemtemplate, DownloadListener listener) async{
  9. listenerList.add(listener);
  10. ...
  11. }
  12. ...
修改方法:手动取消注册或回调
 
  1. // 移除
  2. staticvoid removeDownloadListener(DownloadListener listener) {
  3. if(listener != && listenerList != && listenerList.contains(listener)) {
  4. listenerList.remove(listener);
  5. }
  6. }
  • 资源未关闭或释放导致内存泄露,例如ImageStream的图片资源有没有被正常关闭导致的内存泄漏 。
问题代码:
 
  1. void _resolveImage {
  2. finalImageStream newStream =
  3. widget.image.resolve(createLocalImageConfiguration(context));
  4. assert(newStream != );
  5. _updateSourceStream(newStream);
  6. }
修改方法:在图片组件被销毁时正确释放资源
 
  1. @override
  2. void dispose {
  3. ...
  4. _imageInfo.image.dispose;
  5. _imageInfo = ;

  6. super.dispose;
  7. }
  • PlatformAssetBundle.loadString通过asset读取String内容会一直缓存读取的内容,造成内存无法释放
问题代码:
 
  1. /// 通过asset读取Json
  2. Future<Map<String, dynamic>> loadJsonAsset(String assetPath) async{
  3. _rootBundle ??= PlatformAssetBundle;
  4. finalString jsonStr = await _rootBundle.loadString(assetPath);
  5. return json.decode(jsonStr);
  6. }
修改方法:
 
  1. /// 通过asset读取Json
  2. Future<Map<String, dynamic>> loadJsonAsset(String assetPath) async{
  3. _rootBundle ??= PlatformAssetBundle;
  4. finalString jsonStr = await _rootBundle.loadString(assetPath, cache: false);
  5. return json.decode(jsonStr);
  6. }
PlatformAssetBundle继承于CachingAssetBundle,会在app整个生命周期中缓存读取的数据,如果不是需要频繁访问的话建议cache参数设置为false
定位Flutter内存问题很难么?

文章插图