最近,有些朋友問我,到底GICXMLLayout
的效能如何?因此有了本篇文章。另外,考慮到現在Flutter
也比較火,為了不藏私,因此也加入對Flutter
的比較。因此這裡詳細的對三種開發方式進行橫向比較。
注1:
flutter
採用的是最新的1.0.0
版本。
注2:
flutter
的測試都在profile
模式下測試,效能接近release
。
文中用到的測試程式碼可以直接從這裡點選下載
在做比較之前,先確定一個比較的樣例。這裡以如下UI內容為例。
這裡面給出了一個顯示可變高度的列表的案例,這樣的案例比較具有通用性,有圖片的載入、有高度不固定文字的顯示、有高度不固定CellHeight的計算等等。下面針對這樣的案例,從各種角度來比較分析在不同的開發方式下的比較。
1. 啟動時間
測試平臺是iPhoneX
,iOS 12.0
,因為做的是橫向比較,因此不在多裝置上進行測試,只在iPhoneX
上進行測試分析。
啟動時間的比較由兩個方面組成。
main
之前main
函式之前的時間表示的是iOS對動態連結庫的載入、系統載入等所耗時間。這個時間通過新增DYLD_PRINT_STATISTICS
巨集來獲得。main
函式之後main
函式之後的時間通過main
函式和applicationDidBecomeActive:
方法的時間差來獲得。
另外,為了公平起見,測試方式採用的profile
的方式測試。
主要是考慮到
Flutter
在release
和debug
兩種模式下的效能差異太大,而release
和profile
兩種模式很接近,因此採用profile
的方式
另外,測試載入的資料為11條,時間單位為(秒)
原生
main
函式之前的時間範例
Total pre-main time: 205.82 milliseconds (100.0%)
dylib loading time: 191.47 milliseconds (93.0%)
rebase/binding time: 0.29 milliseconds (0.1%)
ObjC setup time: 6.29 milliseconds (3.0%)
initializer time: 7.76 milliseconds (3.7%)
slowest intializers :
libSystem.B.dylib : 4.67 milliseconds (2.2%)
複製程式碼
main之前 | mian之後 | 總計 |
---|---|---|
0.201 | 0.099 | 0.3 |
0.206 | 0.086 | 0.292 |
0.210 | 0.092 | 0.302 |
0.197 | 0.089 | 0.286 |
0.195 | 0.098 | 0.293 |
平均 | 0.294 |
以上資料是原生APP的啟動時間,平均
0.294秒
GICXMLLayout
main
函式之前的時間範例
Total pre-main time: 342.71 milliseconds (100.0%)
dylib loading time: 291.83 milliseconds (85.1%)
rebase/binding time: 1.55 milliseconds (0.4%)
ObjC setup time: 15
.76 milliseconds (4.5%)
initializer time: 33.48 milliseconds (9.7%)
slowest intializers :
libSystem.B.dylib : 7.05 milliseconds (2.0%)
AsyncDisplayKit : 42.27 milliseconds (12.3%)
複製程式碼
main之前 | mian之後 | 總計 |
---|---|---|
0.318 | 0.066 | 0.384 |
0.342 | 0.069 | 0.411 |
0.338 | 0.066 | 0.404 |
0.337 | 0.067 | 0.404 |
0.330 | 0.064 | 0.394 |
平均 | 0.399 |
Flutter
main
函式之前的執行時間範例
Total pre-main time: 206.08 milliseconds (100.0%)
dylib loading time: 189.66 milliseconds (92.0%)
rebase/binding time: 0.82 milliseconds (0.3%)
ObjC setup time: 7.52 milliseconds (3.6%)
initializer time: 8.06 milliseconds (3.9%)
slowest intializers :
libSystem.B.dylib : 4.61 milliseconds (2.2%)
複製程式碼
main之前 | mian之後 | 總計 |
---|---|---|
0.218 | 0.115 | 0.333 |
0.203 | 0.105 | 0.308 |
0.209 | 0.113 | 0.322 |
0.211 | 0.110 | 0.321 |
0.203 | 0.107 | 0.310 |
平均 | 0.319 |
分析
通過以上三種開發方式的資料分析可以看出,
- 啟動時間最短的是
原生應用
,最長的是GIC
的應用。 GIC
之所以最長,是因為在main
函式之前載入了太多的第三方庫,但是可以看到main
函式之後的執行時間是最短的。flutter
在release
模式下的main
函式之前的載入時間跟原生應用可以說相差無幾,從這裡可以看出,大廠就是大廠,技術能力不得不服。flutter
在main
函式之後的執行時間是三種方式中是最長的。flutter
的引擎、UI、GPU相關的操作都有專門的執行緒負責,區別於iOS
中的UI執行緒
。而flutter
在main
函式之後的執行時間卻是最長的,那麼說明,flutter
有些初始化操作可能是在iOS的UI執行緒
中執行的。考慮到Flutter
app載入了一個Flutter.framework
,並且包含了對iOS
平臺呼叫的程式碼(FlutterAppDelegate
、FlutterViewController
等),因此初步判斷是這個庫中的程式碼的執行結果。GIC
的main
之後執行時間最短應該說是情理之中,因為GIC
的列表佈局
、渲染
等都在非UI執行緒執行的(得益於Texture
)。也就是說,GIC
在UI執行緒上做的事情是在三種開發方式中最少的。
從這裡也可以看出,GIC
的問題在於對第三方庫的依賴太多,後續考慮如何減少對第三方庫的依賴,事實上目前已經在做對RAC
庫的剝離工作,相信剝離後會進一步的提升載入速度。
原生應用
在載入列表的時候採用的是最粗暴的方法,沒有任何的優化,沒有height快取,沒有在後臺執行緒做height計算等等,因此原生應用在啟動時間方面也有進一步的優化空間。但是排名不會發生變化,最多就是mian
函式後的執行時間會縮短,但不會短過GIC
。
2. 幀率
、CPU
、GPU
這三項資料的測試在iPhoneX上看不出明顯的不同,因此這裡就以iphone 6
的測試資料為準。
測試方式:不停的滑動列表
原生
GICXMLLayout
flutter
分析
- 幀率:
在幀率方面,三種方式都差不多,基本上都能維持滿幀。
- CPU:
CPU佔用率從高到低排名為:
flutter
(平均14%) > 原生(平均10%) >GIC
(平均7%)。 - GPU:
GPU佔用率從高到低排名為:
flutter
(平均22%) > 原生(平均16%) >GIC
(平均12%)。跟CPU的結果差不多,flutter
在滑動的時候GPU耗費也高達22%,比最低的GIC
差不多高了一倍。
這一輪的測試中,flutter
基本上算是完敗了,不是百分之多少的差距,而是成倍的差距。
GIC
在UI層是基於Textrue
開發的,因此繼承了Textrue
的所有優點。在這一輪測試中可以說完勝。
3. 記憶體佔用
測試方式:頁面載入完成後滑動列表,然後靜置一段時間 測試裝置:iphone6
原生
GICXMLLayout
flutter
flutter
依然是以profile
模式測試。
分析
由上面三張圖看出,flutter
(40MB)佔用的記憶體最多,GIC
(13.7MB)次之,原生
(9MB)應用佔用最少。
- 可以看出
flutter
佔用了40MB,比原生應用多了將近3倍都不止。 - 而
GIC
佔用了13.7MB
。由於
GIC
在基於Texuture
封裝的時候把佈局元素也作為UI元素
封裝了,因此導致實際的記憶體佔用稍微高了點。
另外,GIC
在使用的過程中建立了JSContext
,你可以理解為JS引擎。而在實際使用過程中,JS並沒有佔用太多的記憶體。當然,這裡面涉及到JS功能也比較少,因此也無法直接說JS佔用記憶體地。
4. 包大小。
為了公平起見,這裡的測試基於release
模式下測試。另外,在開啟和關閉bitcode
兩種模式下,包的大小差距會很大。這裡分別給出。
另外,測試應用已經踢除了靜態圖片資源。
原生
- 開啟
bitcode
:1.1MB - 關閉
bitcode
:269KB
GICXMLLayout
- 開啟
bitcode
:16.2MB - 關閉
bitcode
:3.7MB
flutter
flutter
本身就不支援bitcode。因此忽略bitcode。包的大小為:11MB
分析
通過上面的資料可以分析出,在關閉bitcode的情況下,包的大小依次為,flutter
(11MB) > GIC
(3.7MB) > 原生(269KB)。
5. 動畫
這裡以一個簡單的水平位移動畫作為案例。
測試裝置:iphone6原生
使用CABasicAnimation
做動畫。
GICXMLLayout
flutter
分析
對於這麼簡單的動畫,都是滿幀執行的。因此只需要對GPU和CPU做分析比較即可。
原生
:原生方式的效能表現是最好的。在動畫的時候,幾乎不佔用CPU資源。而GPU一直保持著7%的佔用。
GICXMLLayout
:GIC
的GPU的佔用上跟原生的差不多,但是CPU卻一直有佔用,差不多維持著最高10%
的佔用。並且可以注意到,CPU的佔用不是連續的而是斷斷續續的,這是有原因的,因為GIC
的動畫是基於popAnimation
實現的,而popAnimation
是基於CADisplaylink
開發的,並且是按照60幀計算的。也就是差不多每秒60次的動畫計算。而只有在動畫計算的時候才會佔用CPU資源,因此從測試結果來看,也是符合預期的。另外,在記憶體佔用方面,跟原生動畫差不多。flutter
flutter
的動畫在GPU的佔用上幾乎是原生的兩倍以上。而且CPU也是連續維持著10%的佔用。而記憶體佔用方面也差不多是原生的兩倍以上。
總結
在上面的測試中,由於測試案例比較簡單,並不能代表大多數情況,只是針對當前的測試案例得出的結果,僅僅只是給出一個參考。
對於原生引用的測試程式碼可能有點不公平,沒有進行任何的優化。然而這並不是關鍵,這樣正說明了原生應用的優化空間比較大。
本來還想做一個列表載入時間
測試的,但是對於flutter
卻無從下手,暫時不知道如何測試,等以後有方法了再做測試。
另外,這裡也不得不為我自己的GICXMLLayout
做個宣傳。作為一個獨立開發者維護的一個開源庫並不容易,我花了很多的心血在這上面。各位,如果覺得GIC
這個庫還可以,還希望能給個star
,感謝!。專案地址
拋開原生應用不談,如果您想像前端開發一樣開發IOS應用,那麼我覺得GIC
值得您一試。不管從開發效率、上手難度、程式碼可讀性等方面來說,GIC
都能有優秀的表現,而GIC
目前相較於flutter
等支援跨平臺的庫來說最大的缺點是不支援跨平臺。如果您開發的應用不考慮跨平臺開發的話,那麼GIC
是一個很好的選擇。
有的朋友可能會說,現在flutter很流行,並且
dart
的效率比JS
高。但是GIC
在UI
和業務邏輯(ViewModel)
上是兩套完全不同的架構,UI
是純native的並且是基於Texuture
開發的,而ViewModel
你既可以使用native
程式碼來寫,也支援使用JS
來寫。另外在實際的應用(非遊戲)開發中,業務邏輯如果複雜到能通過不同的語言來區分的地步(比如dart和JS),那麼這樣的應用應該是一個非常複雜的應用了。因此我認為在語言上來比較孰優孰慮並不是最優先順序。另外,事實上GIC
從架構設計上其實也可以支援dart
語言、甚至其他的指令碼語言。