基于跨端框架項目的內(nèi)存問題優(yōu)化
寫在前面
目前,業(yè)內(nèi)的跨端框架不少:react-native,weex,hippy,taro等等。采用跨端框架的項目一般都依附于客戶端而存在,由前端同學開發(fā)。為了避免客戶端發(fā)生crash,相對于傳統(tǒng)瀏覽器上的前端頁面開發(fā),跨端項目對于內(nèi)存管理、CPU利用率的要求更高。
本文將以某App上的小說閱讀器為例,講解在對項目代碼完全不了解的情況下,如何進行內(nèi)存問題的優(yōu)化。
小說的用戶場景比較簡單:打開一部小說,一直滑動閱讀即可。
前期工作
第一步,我們需要工具,來量化項目的內(nèi)存表現(xiàn)。perfdog 是常用的工具之一。使用很簡單,手機連上電腦,打開perdog,打開想要測試的應用,進行操作,就可以看到實時的內(nèi)存和CPU表現(xiàn)了。
由于虛擬內(nèi)存達到某一個臨界值后,會導致APP直接crash;所以需要明確最重要的衡量指標:1、一頓操作后的虛擬內(nèi)存增量。2、峰值虛擬內(nèi)存;
開始優(yōu)化
優(yōu)化方向
前文已經(jīng)講到,我們優(yōu)化的衡量指標是:虛擬內(nèi)存峰值、增量
造成內(nèi)存增加的原因主要是:
1、業(yè)務需要,在內(nèi)存里面儲存了業(yè)務數(shù)據(jù)
2、內(nèi)存泄露導致無法按預期進行GC
對于第一點,并不具有普適性,需要具體情況具體分析。第二點是我們優(yōu)化的著重發(fā)力點。
優(yōu)化步驟
以react為例,說起內(nèi)存問題優(yōu)化(避免內(nèi)存泄露),方法都耳熟能詳:
1、定時器需要清除 ; 2、注意閉包的使用;3、組件銷毀時需要清除對其的引用;4、使用發(fā)布訂閱模式時,組件銷毀時,需要移除事件監(jiān)聽;5、注意全局變量的使用。。。。。
但是在對業(yè)務代碼完全不熟悉,并且業(yè)務代碼量巨大時,直接從幾萬行代碼入手或許不是最好的選擇。
1、采集內(nèi)存增量
怎么找到可優(yōu)化或者說內(nèi)存泄露的地方呢?perfdog可以幫助我們查看實時內(nèi)存,但是沒有辦法細化到具體的內(nèi)存。作為前端開發(fā),我們可以利用常用的chrome inspector的內(nèi)存快照工具幫助我們進行分析。
我們想要測試的是內(nèi)存增量。在開始操作前,先記錄一次內(nèi)存快照。接著模擬用戶,進行一系列操作。操作完成后,手動觸發(fā)一次gc,再記錄一次內(nèi)存快照。查看這兩次快照之間的差異,來判斷內(nèi)存增量的由來。
至此,我們就可以看到我們的操作所帶來的內(nèi)存增量了。接下來開始進行分析。
2、分析內(nèi)存增量
以本文提及的小說場景為例,在滑動了小說幾個章節(jié)后,發(fā)現(xiàn)某組件對象數(shù)量增加了很多,但是一個也沒有被刪除。點開其中一個對象實例,查看其引用鏈,發(fā)現(xiàn)被其外層組件所引用了。
通過關(guān)鍵變量名,可以迅速定位到問題代碼,進行修復。最終發(fā)現(xiàn)父組件中,有一個變量持有了所有的子組件,導致被銷毀的子組件無法被GC,造成泄漏。
再舉一個例子:
從上面的圖中我們可以發(fā)現(xiàn),Promise實例數(shù)也是只增加,不減少。點開其中一個Promise進行排查,發(fā)現(xiàn)大量Promise一直處于pending狀態(tài)。這里肯定是有問題的。
其余不少組件也存在實例數(shù)只增加不減少的情況,點開其中一個組件發(fā)現(xiàn):
組件內(nèi)部引用的Promise一直pending,導致該組件也被系統(tǒng)一直持有了,無法釋放,一切都是卡住的Promise的鍋。
通過查看Promise的持有鏈,最終發(fā)現(xiàn)是由于一個Bug,導致了部分Promise一直無法resolve或reject,導致了內(nèi)存泄露。修復Bug后,問題解決。
這里舉了兩個例子,說明了如何利用內(nèi)存快照進行問題分析,總結(jié)一下:
拿到內(nèi)存增量后,我們需要重點關(guān)注那些新增數(shù)量特別多,但是刪除數(shù)量特別少的對象,很可能其中就有內(nèi)存泄露,或者有明顯的優(yōu)化空間。
3、采集數(shù)據(jù)、分析優(yōu)化效果
優(yōu)化完成后,如何衡量優(yōu)化效果呢?用數(shù)據(jù)說話。chrome inspector一般是用來調(diào)試的,嚴謹?shù)牟杉瘮?shù)據(jù)需要借助其他工具。文章開頭我們介紹了perfdog的使用方法,但是這里用人工來測試是不太現(xiàn)實的,我們可以使用簡單的工具來輔助我們進行測試。
以Android為例,
1、首先安裝adb工具,安裝教程:https://www.jianshu.com/p/1b3fb1f27b67
2、接著連接手機,切換到想要測試的場景,使用 adb shell 來輔助測試。
以小說閱讀場景為例,使用下面的命令可以控制測試手機自動翻頁:
adb shell "input swipe 1000 1300 50 1300 1000"
3、然后我們可以使用Node.js寫一個簡單的腳本,就可以開啟簡陋的“自動化”測試了。下面就是一個自動左右滑動小說1000頁的簡易腳本
4、再結(jié)合perfdog,我們就可以得到內(nèi)存和CPU的表現(xiàn)數(shù)據(jù)了。perfdog可以將數(shù)據(jù)導出成excel文件,開始采集數(shù)據(jù)時,點擊perfdog右上角的開始按鈕,結(jié)束時點擊暫停按鈕,即可導出數(shù)據(jù)。數(shù)據(jù)里面包括了每一秒鐘的CPU、內(nèi)存表現(xiàn)。
最后,通過人工或腳本的方法,便可以很方便的統(tǒng)計出虛擬內(nèi)存增量,峰值虛擬內(nèi)存,最終產(chǎn)出優(yōu)化效果報告。
注意,采集數(shù)據(jù)的時候,需要等待客戶端內(nèi)存穩(wěn)定后再開始,否則對最后的結(jié)果會產(chǎn)生較大影響。并且,每一次測試,需要固定測試路徑,排除其他變量帶來的干擾。
寫在后面
本文主要是從一個前端工程師的角度,以基于跨端框架的項目為例,說明了如何實施一次內(nèi)存問題優(yōu)化。更進一步,可以和客戶端同學配合,達到更加深度的優(yōu)化效果。
在對項目代碼完全不了解的情況下,我們可能無法直接從代碼入手,一行一行死磕??梢越柚ぞ撸凑毡疚牡乃悸愤M行分析,然后再對癥下藥。這是一項有跡可循的系統(tǒng)性工程。至于網(wǎng)絡上的大部分優(yōu)化寶典,更多的是作用于開發(fā)階段。在開發(fā)時就應該養(yǎng)成良好的編碼習慣和意識,最大限度的避免問題的發(fā)生。
本文轉(zhuǎn)載自微信公眾號「符合預期的CoyPan」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系符合預期的CoyPan公眾號。