內(nèi)存泄漏分析總結(jié)

一、背景

測試人員發(fā)現(xiàn)一個(gè)問題,就是反復(fù)快速進(jìn)入詳情頁就會(huì)導(dǎo)致詳情頁崩潰,或者是app圖標(biāo)全部不可見。

二、解決過程

首先初步判斷肯定是有性能問題,要么是內(nèi)存太大,要么是內(nèi)存泄漏了。

1.我們通過devTools查看彩頁內(nèi)存

image.png

a、點(diǎn)擊Menory。b、多次反復(fù)進(jìn)入退出頁面。c、點(diǎn)擊GC主動(dòng)揮手回收對(duì)象。d、篩選我們的頁面

發(fā)現(xiàn)存在多個(gè)頁面對(duì)象。肯定是內(nèi)存泄漏了

2.初步解決一些常見的內(nèi)存泄漏問題

a、圖片占用內(nèi)存過大有可能導(dǎo)致內(nèi)存泄漏,對(duì)圖片做了一系列優(yōu)化,防止內(nèi)存過大;以及把圖片相關(guān)需要釋放的都在頁面關(guān)閉時(shí)釋放掉。

b、把頁面里面其他需要釋放的一些對(duì)象,全部釋放掉了,減少部分內(nèi)存泄漏。

經(jīng)過測試,之前幾次就會(huì)導(dǎo)致頁面內(nèi)存爆炸,現(xiàn)在需要三十多次才會(huì)導(dǎo)致內(nèi)存爆炸。

3.還有其他內(nèi)存泄漏源,繼續(xù)查找

初步懷疑是getx框架有問題,所以在嘗試getx哪里有問題。發(fā)現(xiàn)getx中的_routesKey會(huì)直接會(huì)導(dǎo)致頁面不會(huì)被釋放掉,加了如下一行代碼,可以釋放掉頁面。

image.png

修改后,有的是可以釋放掉頁面,有的仍然無法釋放。

所以getx確實(shí)會(huì)導(dǎo)致頁面無法釋放,導(dǎo)致內(nèi)存泄漏,但是代碼里面也還存在內(nèi)存泄漏。

4.繼續(xù)查找頁面里面內(nèi)存泄漏

由于頁面中組件有幾十個(gè),設(shè)計(jì)的面積比較廣,所以很難直接定位到。于是進(jìn)一和我繼續(xù)通過devtools查看內(nèi)存以及對(duì)比內(nèi)存差異,期望找到突破點(diǎn)。但是內(nèi)存里面的對(duì)象有上百個(gè),很難定位到底是哪一個(gè),起初還誤以為是attr和loader,因?yàn)樗麄冃孤┖芏鄬?duì)象。但是實(shí)際很難說是他們泄漏導(dǎo)致頁面泄漏,還是頁面泄漏導(dǎo)致這些對(duì)象泄漏。

最后我開始分析頁面返回的數(shù)據(jù),決定一個(gè)卡片去試,通過devtools分析可以判斷出是哪一個(gè)卡片泄漏,找到卡片泄漏后,再一個(gè)組件去試,找到Image組件導(dǎo)致內(nèi)存泄漏,最后再通過局部注釋代碼,最終定位到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就是一個(gè)InheritedWidget子類,所以他是PImageWidge的父類。在PImageWidge持有PreviewPptInheritWidget對(duì)象,就會(huì)導(dǎo)致循環(huán)引用,最終導(dǎo)致內(nèi)存泄漏。

所以大家后續(xù)如果使用InheritedWidget系列組件,最好不要持有(成員變量),如果非要持有,就需要在dispose的時(shí)候把InheritedWidget系列對(duì)象置空。

ios的同學(xué)可能非常熟悉循環(huán)引用,android同學(xué)之前幾乎遇不到循環(huán)引用,android的同學(xué)可能要特別注意。

----------------------后續(xù)補(bǔ)充-------------------
后續(xù)又發(fā)現(xiàn)采用navigator.pop()退出頁面不會(huì)出現(xiàn)內(nèi)存泄漏。
如果是使用navigator.removeRoute()退出后臺(tái)的某個(gè)頁面,只會(huì)關(guān)閉頁面,但是頁面會(huì)出現(xiàn)內(nèi)存泄漏。
大概是pop會(huì)去回收頁面等完整流程,removeRoute只是移除路由。
有對(duì)這個(gè)十分了解的同學(xué),也可以評(píng)論區(qū)交流

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容