溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

分析Flutter應(yīng)用性能檢測(cè)與優(yōu)化

發(fā)布時(shí)間:2021-11-04 16:57:04 來(lái)源:億速云 閱讀:175 作者:iii 欄目:web開(kāi)發(fā)

這篇文章主要介紹“分析Flutter應(yīng)用性能檢測(cè)與優(yōu)化”,在日常操作中,相信很多人在分析Flutter應(yīng)用性能檢測(cè)與優(yōu)化問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”分析Flutter應(yīng)用性能檢測(cè)與優(yōu)化”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!

圖層分析

Flutter運(yùn)行模式

1、Debug

Debug模式可以在真機(jī)和模擬器上同時(shí)運(yùn)行,此模式會(huì)打開(kāi)所有的斷言,包括debugging信息、debugger aids(比如observatory)和服務(wù)擴(kuò)展。優(yōu)化了快速develop/run循環(huán),但是沒(méi)有優(yōu)化執(zhí)行速度、二進(jìn)制大小和部署。命令flutter run就是以這種模式運(yùn)行的,通過(guò)sky/tools/gn --android或者sky/tools/gn --ios來(lái)構(gòu)建應(yīng)用的。

2、Release

Release模式只能在真機(jī)上運(yùn)行,不能在模擬器上運(yùn)行:會(huì)關(guān)閉所有斷言和debugging信息,關(guān)閉所有debugger工具。優(yōu)化了快速啟動(dòng)、快速執(zhí)行和減小包體積。禁用所有的debugging aids和服務(wù)擴(kuò)展。這個(gè)模式是為了部署給最終的用戶(hù)使用。命令flutter run --release就是以這種模式運(yùn)行的,通過(guò)sky/tools/gn --android --runtime-mode=release或者sky/tools/gn --ios --runtime-mode=release來(lái)構(gòu)建應(yīng)用。

3、Profile

Profile模式只能在真機(jī)上運(yùn)行,不能在模擬器上運(yùn)行,基本和Release模式一致,除了啟用了服務(wù)擴(kuò)展和tracing,以及一些為了最低限度支持tracing運(yùn)行的東西(比如可以連接observatory到進(jìn)程)。命令flutter run --profile就是以這種模式運(yùn)行的,通過(guò)sky/tools/gn --android --runtime-mode=profile或者sky/tools/gn --ios --runtime-mode=profile來(lái)構(gòu)建應(yīng)用。

4、test

headless test模式只能在桌面上運(yùn)行,基本和Debug模式一致,除了是headless的而且你能在桌面運(yùn)行。命令flutter test就是以這種模式運(yùn)行的,通過(guò)sky/tools/gn來(lái)build。

在實(shí)際開(kāi)發(fā)中,應(yīng)該用到上面所說(shuō)的四種模式又各自分為兩種:一種是未優(yōu)化的模式,供開(kāi)發(fā)人員調(diào)試使用;一種是優(yōu)化過(guò)的模式,供最終的開(kāi)發(fā)人員使用。默認(rèn)情況下是未優(yōu)化模式,如果要開(kāi)啟優(yōu)化模式,build的時(shí)候在命令行后面添加--unoptimized參數(shù)。

不管是移動(dòng)開(kāi)發(fā)還是前端開(kāi)發(fā),對(duì)于性能問(wèn)題分析的思路都是先分析并定位問(wèn)題,F(xiàn)lutter也不例外,借助Flutter 提供的度量性能工具,我們可以快速定位代碼中的性能問(wèn)題,而性能圖層就是幫助我們確認(rèn)問(wèn)題影響范圍的利器,它類(lèi)似Android的圖層分析工具。

為了使用性能圖層,F(xiàn)lutter提供了分析(Profile)模式,與調(diào)試代碼可以通過(guò)模擬器在調(diào)試模式下找到代碼邏輯 Bug 不同,性能問(wèn)題需要在發(fā)布模式下使用真機(jī)進(jìn)行檢測(cè)。相比發(fā)布(Release)模式而言,調(diào)試模式增加了很多額外的檢查(比如斷言),這些檢查可能會(huì)耗費(fèi)很多資源;更重要的是,調(diào)試模式使用 JIT (即時(shí)編譯)模式運(yùn)行應(yīng)用,代碼執(zhí)行效率較低。這就使得調(diào)試模式運(yùn)行的應(yīng)用,無(wú)法真實(shí)反映出它的性能問(wèn)題。

而另一方面,模擬器使用的指令集為 x86,而真機(jī)使用的指令集是 ARM,由于這兩種方式的二進(jìn)制代碼執(zhí)行行為完全不同,因此模擬器與真機(jī)的性能差異較大。一些 x86 指令集擅長(zhǎng)的操作模擬器會(huì)比真機(jī)快,而另一些操作則會(huì)比真機(jī)慢,這也使得我們無(wú)法使用模擬器來(lái)評(píng)估真機(jī)才能出現(xiàn)的性能問(wèn)題。

為了調(diào)試性能問(wèn)題,我們需要在發(fā)布模式的基礎(chǔ)之上,為分析工具提供少量必要的應(yīng)用追蹤信息,這就是分析模式。除了一些調(diào)試性能問(wèn)題必須的追蹤方法之外,F(xiàn)lutter 應(yīng)用的分析模式和發(fā)布模式的編譯和運(yùn)行是類(lèi)似的,只是啟動(dòng)參數(shù)變成了 profile 而已。我們可以在 Android Studio 中通過(guò)菜單欄點(diǎn)擊 【Run】-【Profile 】‘main.dart’ 選項(xiàng)啟動(dòng)應(yīng)用,也可以通過(guò)命令行參數(shù) flutter run --profile 運(yùn)行 Flutter 應(yīng)用。

渲染問(wèn)題分析

在完成了應(yīng)用啟動(dòng)之后,接下來(lái)我們就可以利用 Flutter 提供的渲染問(wèn)題分析工具,即性能圖層(Performance Overlay)來(lái)分析渲染問(wèn)題了。性能圖層會(huì)在當(dāng)前應(yīng)用的最上層,以 Flutter 引擎自繪的方式展示 GPU 與 UI 線程的執(zhí)行圖表,而其中每一張圖表都代表當(dāng)前線程最近 300 幀的表現(xiàn),如果 UI 產(chǎn)生了卡頓(跳幀),這些圖表可以幫助我們分析并找到原因,如下圖所示。

分析Flutter應(yīng)用性能檢測(cè)與優(yōu)化

上圖演示了性能圖層的展現(xiàn)樣式。其中,GPU 線程的性能情況在上面,UI 線程的情況顯示在下面,藍(lán)色垂直的線條表示已執(zhí)行的正常幀,綠色的線條代表的是當(dāng)前幀。

同時(shí),為了保持 60Hz 的刷新頻率,GPU 線程與 UI 線程中執(zhí)行每一幀耗費(fèi)的時(shí)間都應(yīng)該小于 16ms(1/60 秒)。在這其中有一幀處理時(shí)間過(guò)長(zhǎng),就會(huì)導(dǎo)致界面卡頓,圖表中就會(huì)展示出一個(gè)紅色豎條,如下圖所示。

分析Flutter應(yīng)用性能檢測(cè)與優(yōu)化

如果紅色豎條出現(xiàn)在 GPU 線程圖表,意味著渲染的圖形太復(fù)雜,導(dǎo)致無(wú)法快速渲染;而如果是出現(xiàn)在了 UI 線程圖表,則表示 Dart 代碼消耗了大量資源,需要優(yōu)化代碼執(zhí)行時(shí)間。

GPU問(wèn)題定位

GPU渲染問(wèn)題主要集中在底層渲染耗時(shí)上,有時(shí)候 Widget 樹(shù)雖然構(gòu)造起來(lái)容易,但在 GPU 線程下的渲染卻很耗時(shí)。例如,涉及 Widget 裁剪、蒙層這類(lèi)多視圖疊加渲染,或是由于缺少緩存導(dǎo)致靜態(tài)圖像的反復(fù)繪制,都會(huì)明顯拖慢 GPU 的渲染速度。

接下來(lái),使用性能圖層提供的兩項(xiàng)參數(shù),即檢查多視圖疊加的視圖渲染開(kāi)關(guān) checkerboardOffscreenLayers和檢查緩存的圖像開(kāi)關(guān)checkerboardRasterCacheImages來(lái)檢查這兩種情況。

checkerboardOffscreenLayers

多視圖疊加通常會(huì)用到 Canvas 里的 savaLayer 方法,這個(gè)方法在實(shí)現(xiàn)一些特定的效果(比如半透明)時(shí)非常有用,但由于其底層實(shí)現(xiàn)會(huì)在 GPU 渲染上涉及多圖層的反復(fù)繪制,因此會(huì)帶來(lái)較大的性能問(wèn)題。

對(duì)于 saveLayer 方法使用情況的檢查,我們只需要在 MaterialApp 的初始化方法中,將 checkerboardOffscreenLayers 開(kāi)關(guān)設(shè)置為 true,分析工具就會(huì)自動(dòng)幫我們檢測(cè)多視圖疊加的情況。使用了 saveLayer 的 Widget 會(huì)自動(dòng)顯示為棋盤(pán)格式,并隨著頁(yè)面刷新而閃爍。不過(guò),saveLayer 是一個(gè)較為底層的繪制方法,因此我們一般不會(huì)直接使用它,而是會(huì)通過(guò)一些功能性 Widget,在涉及需要剪切或半透明蒙層的場(chǎng)景中間接地使用。所以一旦遇到這種情況,我們需要思考一下是否一定要這么做,能不能通過(guò)其他方式來(lái)實(shí)現(xiàn)呢?

比如下面的例子中,我們使用 CupertinoPageScaffold 與 CupertinoNavigationBar 實(shí)現(xiàn)了一個(gè)動(dòng)態(tài)模糊的效果,代碼如下:

CupertinoPageScaffold(    navigationBar: CupertinoNavigationBar(),//動(dòng)態(tài)模糊導(dǎo)航欄      child: ListView.builder(        itemCount: 100,        //為列表創(chuàng)建100個(gè)不同顏色的RowItem        itemBuilder: (context, index)=>TabRowItem(              index: index,              lastItem: index == 100 - 1,              color: colorItems[index],//設(shè)置不同的顏色              colorName: colorNameItems[index],            )      )  );

其中,模糊的NavigationBar效果如下圖所示。

分析Flutter應(yīng)用性能檢測(cè)與優(yōu)化

當(dāng)我們開(kāi)啟checkerboardOffscreenLayers之后,可以看到視圖蒙層效果對(duì)GPU的渲染壓力導(dǎo)致性能視圖頻繁閃動(dòng)。如果我們沒(méi)有對(duì)動(dòng)態(tài)模糊效果有特殊需求,則可以使用不帶模糊效果的 Scaffold 和白色的 AppBar 實(shí)現(xiàn)同樣的產(chǎn)品功能,來(lái)解決這個(gè)性能問(wèn)題。

Scaffold(    //使用普通的白色AppBar    appBar: AppBar(title: Text('Home', style: TextStyle(color:Colors.black),),backgroundColor: Colors.white),    body: ListView.builder(        itemCount: 100,        //為列表創(chuàng)建100個(gè)不同顏色的RowItem        itemBuilder: (context, index)=>TabRowItem(          index: index,          lastItem: index == 100 - 1,          color: colorItems[index],//設(shè)置不同的顏色          colorName: colorNameItems[index],        )    ),  );

運(yùn)行一下代碼,可以看到,在去掉了模糊效果之后,GPU 的渲染壓力得到了緩解,checkerboardOffscreenLayers 檢測(cè)圖層也不再頻繁閃爍了。

分析Flutter應(yīng)用性能檢測(cè)與優(yōu)化

checkerboardRasterCacheImages

從資源的角度看,另一類(lèi)非常消耗性能的操作是渲染圖像,因?yàn)閳D像渲染會(huì)涉及 I/O、GPU 存儲(chǔ)以及不同通道的數(shù)據(jù)格式轉(zhuǎn)換,因此渲染過(guò)程的構(gòu)建需要消耗大量資源。為了緩解 GPU 的壓力,F(xiàn)lutter 提供了多層次的緩存快照,這樣 Widget 重建時(shí)就無(wú)需重新繪制靜態(tài)圖像了。

與檢查多視圖疊加渲染的 checkerboardOffscreenLayers 參數(shù)類(lèi)似,F(xiàn)lutter 提供了檢查緩存圖像的開(kāi)關(guān) checkerboardRasterCacheImages,來(lái)檢測(cè)在界面重繪時(shí)頻繁閃爍的圖像。

為了提高靜態(tài)圖像顯示性能,我們可以把需要靜態(tài)緩存的圖像加到 RepaintBoundary 中,RepaintBoundary 可以確定 Widget 樹(shù)的重繪邊界,如果圖像足夠復(fù)雜,F(xiàn)lutter 引擎會(huì)自動(dòng)將其緩存,從而避免重復(fù)刷新。當(dāng)然,因?yàn)榫彺尜Y源有限,如果引擎認(rèn)為圖像不夠復(fù)雜,也可能會(huì)忽略 RepaintBoundary。下面的代碼展示了通過(guò) RepaintBoundary,將一個(gè)靜態(tài)復(fù)合 Widget 加入緩存的具體用法,如下所示。

RepaintBoundary(//設(shè)置靜態(tài)緩存圖像    child: Center(      child: Container(        color: Colors.black,        height: 10.0,        width: 10.0,      ),  ));

UI 線程問(wèn)題定位

如果說(shuō) GPU 線程問(wèn)題定位的是渲染引擎底層渲染異常,那么 UI 線程問(wèn)題發(fā)現(xiàn)的則是應(yīng)用的性能瓶頸。比如在視圖構(gòu)建時(shí),在 build 方法中使用了一些復(fù)雜的運(yùn)算,或是在主 Isolate 中進(jìn)行了同步的 I/O 操作。這些問(wèn)題,都會(huì)明顯增加 CPU 的處理時(shí)間,拖慢應(yīng)用的響應(yīng)速度。

針對(duì)這類(lèi)問(wèn)題,我們可以使用 Flutter 提供的 Performance 工具,來(lái)記錄應(yīng)用的執(zhí)行軌跡。Performance 是一個(gè)強(qiáng)大的性能分析工具,能夠以時(shí)間軸的方式展示 CPU 的調(diào)用棧和執(zhí)行時(shí)間,去檢查代碼中可疑的方法調(diào)用。

打開(kāi) Android Studio 底部工具欄中的“Open DevTools”按鈕之后,系統(tǒng)會(huì)自動(dòng)打開(kāi) Dart DevTools 的網(wǎng)頁(yè),將頂部的 tab 切換到 Performance 后,我們就可以開(kāi)始分析代碼中的性能問(wèn)題了。

分析Flutter應(yīng)用性能檢測(cè)與優(yōu)化

分析Flutter應(yīng)用性能檢測(cè)與優(yōu)化

接下來(lái),我們通過(guò)一個(gè)在 ListView 中計(jì)算 MD5 的例子來(lái)演示 Performance 的具體分析過(guò)程??紤]到在 build 函數(shù)中進(jìn)行渲染信息的組裝是一個(gè)常見(jiàn)的操作,為了演示Performance的使用過(guò)程,我們故意放大計(jì)算 MD5 的耗時(shí),如循環(huán)迭代計(jì)算了 1 萬(wàn)次。

class MyHomePage extends StatelessWidget {    MyHomePage({Key key}) : super(key: key);    String generateMd5(String data) {      //MD5固定算法      var content = new Utf8Encoder().convert(data);      var digest = md5.convert(content);      return hex.encode(digest.bytes);    }    @override    Widget build(BuildContext context) {      return Scaffold(        appBar: AppBar(title: Text('demo')),        body: ListView.builder(            itemCount: 30,// 列表元素個(gè)數(shù)            itemBuilder: (context, index) {              //反復(fù)迭代計(jì)算MD5              String str = '1234567890abcdefghijklmnopqrstuvwxyz';              for(int i = 0;i<10000;i++) {                str = generateMd5(str);              }              return ListTile(title: Text("Index : $index"), subtitle: Text(str));            }// 列表項(xiàng)創(chuàng)建方法        ),      );    }  }

與性能圖層能夠自動(dòng)記錄應(yīng)用執(zhí)行情況不同,使用 Performance 來(lái)分析代碼執(zhí)行軌跡,我們需要手動(dòng)點(diǎn)擊【Record】按鈕去主動(dòng)觸發(fā),在完成信息的抽樣采集后再點(diǎn)擊【Stop】按鈕結(jié)束錄制,然后就可以得到在這期間應(yīng)用的執(zhí)行情況了。

Performance 記錄的應(yīng)用執(zhí)行情況叫做 CPU 幀圖,又被稱(chēng)為火焰圖。火焰圖是基于記錄代碼執(zhí)行結(jié)果所產(chǎn)生的圖片,用來(lái)展示 CPU 的調(diào)用棧,表示的是 CPU 的繁忙程度。所以,我們要檢測(cè) CPU 耗時(shí)問(wèn)題,皆可以查看火焰圖底部的哪個(gè)函數(shù)占據(jù)的寬度最大。只要有“平頂”,就表示該函數(shù)可能存在性能問(wèn)題,如下圖所示。

分析Flutter應(yīng)用性能檢測(cè)與優(yōu)化

可以看到,_MyHomePage.generateMd5 函數(shù)的執(zhí)行時(shí)間最長(zhǎng),幾乎占滿(mǎn)了整個(gè)火焰圖的寬,而這也與代碼中存在的問(wèn)題是一致的。在找到了問(wèn)題之后,我們就可以使用 Isolate(或 compute)將這些耗時(shí)的操作挪到并發(fā)主 Isolate 之外去完成了。

到此,關(guān)于“分析Flutter應(yīng)用性能檢測(cè)與優(yōu)化”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注億速云網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI