前言
引入weex提高了業務開發的效率以及靈活度,但是在使用過程中還是存在不少問題,其中記憶體上就有很明顯的問題
一、weex頁面與原生頁面對比存在的記憶體問題
1、weex頁面記憶體開銷過大
如圖進行頁面切換:
在進行到weex頁面的時候記憶體暴漲。
2、頁面Push跳轉堆疊記憶體洩漏。
從首頁Push跳轉到weex頁面,載入資料,再返回,重複多次得出下圖的結果:
而Push跳轉到原生頁面再返回,重複多次得出下圖記憶體結果:
從上面兩張圖可以看出:原生頁面返回後從堆疊移除後會進記憶體回收;而從weex頁面回到首頁,記憶體沒有完全回收,存在一定的記憶體洩漏,重複多次可以看到記憶體相比較一開始會有明顯的增加。
3、列表滑動的記憶體情況
在沒有采用和
weex頁面列表滑動記憶體情況如圖:
通過趨勢圖列表滑動過程中記憶體一直持續暴漲,沒有進行復用減少記憶體開銷。
原生頁面列表滑動記憶體情況如圖:
從圖中可以看到,在滑動初始階段,記憶體增長比較快,之後的滑動過程中對前面的控制元件進行復用,記憶體開銷減少,曲線變得平緩,沒有出現記憶體持續暴漲。
4、 weex頁面記憶體問題總結:
1、weex頁面滑動沒有采用複用機制,導致記憶體會跟著滑動持續暴漲
2、weex頁面佔用記憶體開銷過高,多個weex頁面可能導致APP因為記憶體過大而Crash。
3、weex頁面從堆疊移除記憶體沒有完全回收,存在一定的記憶體洩漏。
二、記憶體問題原因分析
1、滑動過程記憶體持續暴漲問題
weex官方文件上,建議使用高效能可複用<cell>
和<list>
,而【搜尋頁】、【樂瘋搶】等weex頁面業務程式碼中直接採用了<div>
和<scroller>
實現列表的佈局,導致記憶體問題的出現。
這裡我們通過Weex原始碼,對四個標籤進行分析
可以在WXSDKEngine
中可以看出各個標籤對應的類:
<div> 對應WXComponent
<scroller>對應WXScrollerComponent
<cell>對應WXCellComponent
<list>對應WXListComponent複製程式碼
<div>
對應的WXComponent
相當於原生iOS控制元件的UIView,是所有檢視的基類,一個普通的檢視沒有效能優化、複用回收的機制。
與<scroller>
對應的WXScrollerComponent
結構如下:
並無相關複用回收的屬性,主要是提供一個可以滑動的容器。
檢視<cell>
對應WXCellComponent
類的實現程式碼可以發現,WXCellComponent
相比較WXComponent
擁有複用回收的相關屬性isRecycle
與<list>
對應的WXListComponent
的結構如圖:
在成員列表中可以看到使用了iOS原生的UITableView,並且實現了使用了UITableView的代理方法,實現了iOS的複用機制,如圖:
同時WXListComponent
實現了WXCellComponent
中的代理方法,WXCellComponent
與WXListComponent
相關聯絡。
因此<list>
基於iOS的UITableView複用機制,實現高效能了可複用的列表容器。
結合<cell>
可以實現一個高效能的列表展示頁面。
因此採用<list>
和<cell>
代替<scroller>
和<div>
解決滑動列表記憶體暴漲的問題。
2、weex頁面記憶體開銷過高的問題
通過Instrument工具進行記憶體分析,發現在進入weex 頁面時VM ImageIO_GIF_Data
和VM ImageIO
兩個物件記憶體異常暴漲。
VM ImageIO_GIF_Data 記憶體增長情況:
VM ImageIO 記憶體增長情況:
VM ImageIO_GIF_Data
由7.92M增長到16.55M,VM ImageIO
由0.11M增長到了1.02M,進入Weex頁面時,這兩個物件總共增加了9.54M,而整個Weex頁面初始狀態佔用記憶體為15M左右(原生【商品詳情】頁:7M左右),佔據了整個Weex頁面記憶體的約60%。
而在原生頁面中,VM ImageIO_GIF_Data
和VM ImageIO
物件幾乎沒有增長。
而這兩個物件與CoreGraphics
中進行圖片繪製、圖片渲染、圖片讀寫等相關方法有關,而CoreGraphics為相對底層的模組,相關方法比較消耗效能、記憶體,並且容易產生記憶體洩漏。
初步可以判定,weex中大量呼叫了CoreGraphics
中圖片處理的相關方法,導致了weex頁面記憶體開銷過大。
接著在WeexSDK的原始碼中查詢CoreGraphics
相關方法,定位問題。
在查詢過程發現,weex通過CoreGraphics繪圖方法將
在 WXComponent+Display
中,可以看到將控制元件繪製成圖片的程式碼,並在layer
上顯示:
通過這部分的程式碼可以定位到weex頁面記憶體開銷過大的主要原因是: weex SDK 呼叫了CoreGraphics
方法將頁面中的等控制元件繪製成圖片再佈局顯示,佔用了大量的記憶體。
weex的記憶體洩漏也與大量呼叫了CoreGraphics
中方法有關。
通過Leaks工具定位到weex頁面記憶體洩漏物件為CGDataProviderCreateWithCopyOfData
而CGDataProviderCreateWithCopyOfData
為呼叫CoreGraphics
相關方法產生的物件。
weex SDK呼叫CoreGraphics
中的相關方法,但是沒有及時地釋放物件,導致了記憶體洩漏。
weex SDK 大量CoreGraphics
方法將控制元件繪製成圖片再佈局顯示,佔用了大量的記憶體,同時也導致了資源回收不及時的問題。
解決方案:
1、限制堆疊中weex頁面個數:
天貓採用的也是該方案,通過控制頁面級數,控制記憶體,防止因為堆疊過多的weex頁面,記憶體過大導致異常Crash。
2、頁面複用:
在開啟weex頁面前,判斷堆疊中是否有該weex頁面,如果有便進行頁面複用,通過資料重新整理頁面,同時通過調整堆疊將頁面顯示出來。