iOS:原生應用 VS Flutter VS GICXMLLayout 比較

搬磚的碼農發表於2019-01-25

最近,有些朋友問我,到底GICXMLLayout的效能如何?因此有了本篇文章。另外,考慮到現在Flutter也比較火,為了不藏私,因此也加入對Flutter的比較。因此這裡詳細的對三種開發方式進行橫向比較。

注1:flutter採用的是最新的1.0.0版本。

注2:flutter的測試都在profile模式下測試,效能接近release

文中用到的測試程式碼可以直接從這裡點選下載

在做比較之前,先確定一個比較的樣例。這裡以如下UI內容為例。

iOS:原生應用 VS Flutter  VS GICXMLLayout  比較

這裡面給出了一個顯示可變高度的列表的案例,這樣的案例比較具有通用性,有圖片的載入、有高度不固定文字的顯示、有高度不固定CellHeight的計算等等。下面針對這樣的案例,從各種角度來比較分析在不同的開發方式下的比較。

1. 啟動時間

測試平臺是iPhoneX,iOS 12.0,因為做的是橫向比較,因此不在多裝置上進行測試,只在iPhoneX上進行測試分析。

啟動時間的比較由兩個方面組成。

  1. main之前

    main函式之前的時間表示的是iOS對動態連結庫的載入、系統載入等所耗時間。這個時間通過新增DYLD_PRINT_STATISTICS巨集來獲得。

  2. main函式之後

    main函式之後的時間通過main函式和applicationDidBecomeActive:方法的時間差來獲得。

另外,為了公平起見,測試方式採用的profile的方式測試。

主要是考慮到Flutterreleasedebug兩種模式下的效能差異太大,而releaseprofile兩種模式很接近,因此採用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

分析

通過以上三種開發方式的資料分析可以看出,

  1. 啟動時間最短的是原生應用,最長的是GIC的應用。
  2. GIC之所以最長,是因為在main函式之前載入了太多的第三方庫,但是可以看到main函式之後的執行時間是最短的。
  3. flutterrelease模式下的main函式之前的載入時間跟原生應用可以說相差無幾,從這裡可以看出,大廠就是大廠,技術能力不得不服。
  4. fluttermain函式之後的執行時間是三種方式中是最長的。

    flutter的引擎、UI、GPU相關的操作都有專門的執行緒負責,區別於iOS中的UI執行緒。而fluttermain函式之後的執行時間卻是最長的,那麼說明,flutter有些初始化操作可能是在iOS的UI執行緒中執行的。考慮到Flutterapp載入了一個Flutter.framework,並且包含了對iOS平臺呼叫的程式碼(FlutterAppDelegateFlutterViewController等),因此初步判斷是這個庫中的程式碼的執行結果。

  5. GICmain之後執行時間最短應該說是情理之中,因為GIC的列表佈局渲染等都在非UI執行緒執行的(得益於Texture)。也就是說,GIC在UI執行緒上做的事情是在三種開發方式中最少的。

從這裡也可以看出,GIC的問題在於對第三方庫的依賴太多,後續考慮如何減少對第三方庫的依賴,事實上目前已經在做對RAC庫的剝離工作,相信剝離後會進一步的提升載入速度。

原生應用在載入列表的時候採用的是最粗暴的方法,沒有任何的優化,沒有height快取,沒有在後臺執行緒做height計算等等,因此原生應用在啟動時間方面也有進一步的優化空間。但是排名不會發生變化,最多就是mian函式後的執行時間會縮短,但不會短過GIC

2. 幀率CPUGPU

這三項資料的測試在iPhoneX上看不出明顯的不同,因此這裡就以iphone 6的測試資料為準。

測試方式:不停的滑動列表

原生

iOS:原生應用 VS Flutter  VS GICXMLLayout  比較

iOS:原生應用 VS Flutter  VS GICXMLLayout  比較

GICXMLLayout

iOS:原生應用 VS Flutter  VS GICXMLLayout  比較

iOS:原生應用 VS Flutter  VS GICXMLLayout  比較

flutter

iOS:原生應用 VS Flutter  VS GICXMLLayout  比較

iOS:原生應用 VS Flutter  VS GICXMLLayout  比較

分析

  1. 幀率:

    在幀率方面,三種方式都差不多,基本上都能維持滿幀。

  2. CPU:

    CPU佔用率從高到低排名為:flutter(平均14%) > 原生(平均10%) > GIC(平均7%)。

  3. GPU:

    GPU佔用率從高到低排名為:flutter(平均22%) > 原生(平均16%) > GIC(平均12%)。跟CPU的結果差不多,flutter在滑動的時候GPU耗費也高達22%,比最低的GIC差不多高了一倍。

這一輪的測試中,flutter基本上算是完敗了,不是百分之多少的差距,而是成倍的差距。

GIC在UI層是基於Textrue開發的,因此繼承了Textrue的所有優點。在這一輪測試中可以說完勝。

3. 記憶體佔用

測試方式:頁面載入完成後滑動列表,然後靜置一段時間 測試裝置:iphone6

原生

iOS:原生應用 VS Flutter  VS GICXMLLayout  比較

GICXMLLayout

iOS:原生應用 VS Flutter  VS GICXMLLayout  比較

flutter

flutter依然是以profile模式測試。

iOS:原生應用 VS Flutter  VS GICXMLLayout  比較

分析

由上面三張圖看出,flutter(40MB)佔用的記憶體最多,GIC(13.7MB)次之,原生(9MB)應用佔用最少。

  1. 可以看出flutter佔用了40MB,比原生應用多了將近3倍都不止。
  2. GIC佔用了13.7MB

    由於GIC在基於Texuture封裝的時候把佈局元素也作為UI元素封裝了,因此導致實際的記憶體佔用稍微高了點。

另外,GIC在使用的過程中建立了JSContext,你可以理解為JS引擎。而在實際使用過程中,JS並沒有佔用太多的記憶體。當然,這裡面涉及到JS功能也比較少,因此也無法直接說JS佔用記憶體地。

4. 包大小。

為了公平起見,這裡的測試基於release模式下測試。另外,在開啟和關閉bitcode兩種模式下,包的大小差距會很大。這裡分別給出。

另外,測試應用已經踢除了靜態圖片資源。

原生

  1. 開啟bitcode:1.1MB
  2. 關閉bitcode:269KB

GICXMLLayout

  1. 開啟bitcode:16.2MB
  2. 關閉bitcode:3.7MB

flutter

flutter本身就不支援bitcode。因此忽略bitcode。包的大小為:11MB

分析

通過上面的資料可以分析出,在關閉bitcode的情況下,包的大小依次為,flutter(11MB) > GIC(3.7MB) > 原生(269KB)。

5. 動畫

這裡以一個簡單的水平位移動畫作為案例。

iOS:原生應用 VS Flutter  VS GICXMLLayout  比較
測試裝置:iphone6

原生

使用CABasicAnimation做動畫。

iOS:原生應用 VS Flutter  VS GICXMLLayout  比較

GICXMLLayout

iOS:原生應用 VS Flutter  VS GICXMLLayout  比較

flutter

iOS:原生應用 VS Flutter  VS GICXMLLayout  比較

分析

對於這麼簡單的動畫,都是滿幀執行的。因此只需要對GPU和CPU做分析比較即可。

  1. 原生:

    原生方式的效能表現是最好的。在動畫的時候,幾乎不佔用CPU資源。而GPU一直保持著7%的佔用。

  2. GICXMLLayout:

    GIC的GPU的佔用上跟原生的差不多,但是CPU卻一直有佔用,差不多維持著最高10%的佔用。並且可以注意到,CPU的佔用不是連續的而是斷斷續續的,這是有原因的,因為GIC的動畫是基於popAnimation實現的,而popAnimation是基於CADisplaylink開發的,並且是按照60幀計算的。也就是差不多每秒60次的動畫計算。而只有在動畫計算的時候才會佔用CPU資源,因此從測試結果來看,也是符合預期的。另外,在記憶體佔用方面,跟原生動畫差不多。

  3. flutter

    flutter的動畫在GPU的佔用上幾乎是原生的兩倍以上。而且CPU也是連續維持著10%的佔用。而記憶體佔用方面也差不多是原生的兩倍以上。

總結

在上面的測試中,由於測試案例比較簡單,並不能代表大多數情況,只是針對當前的測試案例得出的結果,僅僅只是給出一個參考。

對於原生引用的測試程式碼可能有點不公平,沒有進行任何的優化。然而這並不是關鍵,這樣正說明了原生應用的優化空間比較大。

本來還想做一個列表載入時間測試的,但是對於flutter卻無從下手,暫時不知道如何測試,等以後有方法了再做測試。

另外,這裡也不得不為我自己的GICXMLLayout做個宣傳。作為一個獨立開發者維護的一個開源庫並不容易,我花了很多的心血在這上面。各位,如果覺得GIC這個庫還可以,還希望能給個star,感謝!專案地址

拋開原生應用不談,如果您想像前端開發一樣開發IOS應用,那麼我覺得GIC值得您一試。不管從開發效率、上手難度、程式碼可讀性等方面來說,GIC都能有優秀的表現,而GIC目前相較於flutter等支援跨平臺的庫來說最大的缺點是不支援跨平臺。如果您開發的應用不考慮跨平臺開發的話,那麼GIC是一個很好的選擇。

有的朋友可能會說,現在flutter很流行,並且dart的效率比JS高。但是GICUI業務邏輯(ViewModel)上是兩套完全不同的架構,UI是純native的並且是基於Texuture開發的,而ViewModel你既可以使用native程式碼來寫,也支援使用JS來寫。另外在實際的應用(非遊戲)開發中,業務邏輯如果複雜到能通過不同的語言來區分的地步(比如dart和JS),那麼這樣的應用應該是一個非常複雜的應用了。因此我認為在語言上來比較孰優孰慮並不是最優先順序。另外,事實上GIC從架構設計上其實也可以支援dart語言、甚至其他的指令碼語言。

相關文章