一、背景
測試人員發(fā)現(xiàn)一個(gè)問題,就是反復(fù)快速進(jìn)入詳情頁就會(huì)導(dǎo)致詳情頁崩潰,或者是app圖標(biāo)全部不可見。
二、解決過程
首先初步判斷肯定是有性能問題,要么是內(nèi)存太大,要么是內(nèi)存泄漏了。
1.我們通過devTools查看彩頁內(nèi)存

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ì)被釋放掉,加了如下一行代碼,可以釋放掉頁面。

修改后,有的是可以釋放掉頁面,有的仍然無法釋放。
所以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ū)交流