Weex-iOS 記憶體分析

王小樹發表於2017-09-06

簡書

前言

引入weex提高了業務開發的效率以及靈活度,但是在使用過程中還是存在不少問題,其中記憶體上就有很明顯的問題

一、weex頁面與原生頁面對比存在的記憶體問題

1、weex頁面記憶體開銷過大

如圖進行頁面切換:


在進行到weex頁面的時候記憶體暴漲。

2、頁面Push跳轉堆疊記憶體洩漏。

從首頁Push跳轉到weex頁面,載入資料,再返回,重複多次得出下圖的結果:

而Push跳轉到原生頁面再返回,重複多次得出下圖記憶體結果:

從上面兩張圖可以看出:原生頁面返回後從堆疊移除後會進記憶體回收;而從weex頁面回到首頁,記憶體沒有完全回收,存在一定的記憶體洩漏,重複多次可以看到記憶體相比較一開始會有明顯的增加。

3、列表滑動的記憶體情況

在沒有采用標籤的情況下:

weex頁面列表滑動記憶體情況如圖:

weex頁面滑動記憶體情況
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中的代理方法,WXCellComponentWXListComponent相關聯絡。

因此<list>基於iOS的UITableView複用機制,實現高效能了可複用的列表容器。
結合<cell>可以實現一個高效能的列表展示頁面。

因此採用<list><cell>代替<scroller><div>解決滑動列表記憶體暴漲的問題。

2、weex頁面記憶體開銷過高的問題

通過Instrument工具進行記憶體分析,發現在進入weex 頁面時VM ImageIO_GIF_DataVM 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_DataVM ImageIO物件幾乎沒有增長。
而這兩個物件與CoreGraphics中進行圖片繪製、圖片渲染、圖片讀寫等相關方法有關,而CoreGraphics為相對底層的模組,相關方法比較消耗效能、記憶體,並且容易產生記憶體洩漏。
初步可以判定,weex中大量呼叫了CoreGraphics中圖片處理的相關方法,導致了weex頁面記憶體開銷過大。

接著在WeexSDK的原始碼中查詢CoreGraphics相關方法,定位問題。
在查詢過程發現,weex通過CoreGraphics繪圖方法將等控制元件例項繪製成點陣圖進行顯示,以適應weex中的CSS佈局。
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頁面,如果有便進行頁面複用,通過資料重新整理頁面,同時通過調整堆疊將頁面顯示出來。

相關文章