流言終結者- Flutter和RN誰纔是更好的跨端開發方案?

做者:閒魚技術-燈陽android

背景

論壇上不少小夥伴關心爲何閒魚選擇了Flutter而不選擇其餘跨端方案?站在質量的角度,高性能是一個很重的因素,咱們使用Flutter重寫了寶貝詳情頁以後,對比了Flutter和Native詳情頁的性能表現,結論是中高端機型上Flutter和Native不相上下,在低端機型上,Flutter會比Native更加的流暢,其實閒魚團隊在使用Flutter作詳情頁過程當中,沒有更多地關注性能優化,爲了更快地上線,也是優先功能的實現,不過測試結果出來以後,卻出乎意料地優於原先的Native的實現(具體的測試結果,屬於敏感數據,要走披露流程,傷不起…)git

可是這樣很顯然不能敷衍過去,仔細想了想,確實Flutter的定位並非要替代Native,他只想作一個極致的跨端解決方案,因此仍是要回到跨端解決方案的賽道,給您從性能角度比一比,誰纔是更好的跨端開發方案?github

參賽選手

[Flutter]

Flutter is Google’s mobile app SDK for crafting high-quality native interfaces on iOS and Android in record time. Flutter works with existing code, is used by developers and organizations around the world, and is free and open source.objective-c

[REACT NATIVE]

We're working on a large-scale rearchitecture of React Native to make it more flexible and integrate better with native infrastructure in hybrid JavaScript/native apps.編程

鳴鑼開賽

怎麼比

怎麼比較確實傷腦筋,本身也寫了一個Flutter 和 一個RN的App,可是實在太醜陋,擔憂你們關注點都到個人爛代碼上了,因此在Github上找到了一個跨端開發高手Car Guo,用Flutter和RN分別實現的一個實際可用的App,Car Guo謙虛表示其實也寫的比較粗糙,可是在我看來這個是具有真實使用場景的App(Github客戶端App,提供豐富的功能,旨在更好的平常管理和維護我的Github),仍是有表明性的 [Flutter] github.com/CarGuo/GSYG… [REACT NATIVE] github.com/CarGuo/GSYG…性能優化

場景

一、默認登陸成功 二、「動態」頁,點擊搜索按鈕,搜索關鍵字「Java」,正常速度瀏覽3頁,等第4頁加載完成後回退 三、點擊「趨勢」頁Tab,瀏覽Feeds到頁面底部,點擊最底部的Item,進入Item後,瀏覽詳情+瀏覽3頁的動態後回退,到「個人」Tab頁 四、查看「個人」Feeds到底部,點擊右上角搜索按鈕,搜索關鍵字「C」,瀏覽3頁後,等第4頁加載完成後場景結束app

測試工具

  • iOS
  • 掌中測(iOS端):CPU,內存
  • Instruments:FPS
  • Android
  • 基於Adb的Shell腳本:CPU,內存,FPS

測試機型

  • iOS:iPhone 5c 9.0.1 / iPhone 6s 10.3.2
  • Android:Xiaomi 2s 5.0.2 / Sumsung S8 7.0

數據分析

iOS

iPhone 5c 9.0.1

image.png

iPhone 6s 10.3.2

image.png

測試結論

一、Flutter在低端和中端的iOS機型上,FPS的表現都優於RN 二、CPU的使用上Flutter在低端機上表現略差於RN,中端機型略優於RN 三、值得注意的是內存上的表現(上圖紅色箭頭區域),Flutter在低端機型上的起始內存和RN幾乎一致,在中端機型上會多30M左右的內存(分析爲Dart VM的內存),能夠想到這應該是Flutter針對低端和中端機型上內存策略是不同的,可用內存少的機型,Dart VM的初始內存少,運行時進行分配(這樣也能夠理解爲何在低端機上帶來了更多的CPU損耗),中端機器上預分配了更多的VM內存,這樣在處理時會更加的遊刃有餘,減小CPU的介入,帶來更流暢的體驗. 能夠看出,Flutter團隊在針對不一樣機型上處理更加的細膩,目的就是爲了帶來穩定流暢的體驗。ide

Android

Xiaomi 2s 5.0.2

image.png

Sumsung S8 7.0

image.png

  • 注: MFS - Max Frame Space: 指的是去掉buffer以後的兩幀的時間差

測試結論

一、Flutter在高低端機的CPU上的表現都優於RN,尤爲在低端的小米2s上有着更優的表現 二、Android端在原來FPS基礎上增長了流暢度的指標,FPS和流暢度的表現Flutter優於RN(計算規則見附參考文章) 三、Android端的內存也是值得關注的一點,在小米2s上起始內存Flutter明顯比RN多40M,RN在測試過程當中內存飛漲,Flutter相比之下會更穩定,內存上RN側的代碼是須要調優的,同一套代碼Flutter在Android和iOS上並無很大的差別,可是RN的卻要在單端調優,Flutter在這項比拼上又更勝一籌。 比較奇怪的是三星S8上Flutter和RN的初始內存是一致的,猜想是RN也Android高端機型上也會預分配一些內存,具體細節還須要更進一步的研究。工具

升旗儀式

看了以前的數據,作爲裁判的我會把金牌頒給Flutter,在測試過程當中的體驗和數據上來看Flutter都優於RN,而且開發這個App的是一位Android的開發同窗,Flutter和RN對於他來講都是全新的技術棧,Car Guo同窗更傾向性地讓你們獲得一致性的使用體驗,性能方面並無投入太多的時間進行調優,由此看出Flutter在跨端開發上在一樣投入的狀況下,能夠得到更佳的性能,更好的用戶體驗。性能

一些思考

拿到了這些數據,也感覺到Flutter帶來福利,那Flutter爲何能夠作到這麼流暢呢?Flutter是如何優化了渲染,Dart VM的Runtime是怎麼玩的?請你們繼續關注後續解密文章,感興趣的同窗歡迎加入閒魚,成爲跨端解決方案的領軍者。

參考

  • Android FPS&流暢度: testerhome.com/topics/4775

  • Android 內存獲取方式: dumpsys meminfo packageName

  • Android CPU 經過busybox 執行 top命令獲取

  • iOS CPU獲取方式:累計每一個線程中的CPU利用率

for (j = 0; j < thread_count; j++)
{
ATCPUDO *cpuDO = [[ATCPUDO alloc] init];
char name[256];
pthread_t pt = pthread_from_mach_thread_np(thread_list[j]);
if (pt) {
name[0] = '\0';
__unused int rc = pthread_getname_np(pt, name, sizeof name);
cpuDO.threadid = thread_list[j];
cpuDO.identify = [NSString stringWithFormat:@"%s",name];
} 
thread_info_count = THREAD_INFO_MAX;
kr = thread_info(thread_list[j], THREAD_BASIC_INFO,(thread_info_t)thinfo, &thread_info_count);
if (kr != KERN_SUCCESS) {
return nil;
}
basic_info_th = (thread_basic_info_t)thinfo;
if (!(basic_info_th->flags & TH_FLAGS_IDLE)) {
tot_sec = tot_sec + basic_info_th->user_time.seconds + basic_info_th->system_time.seconds;
tot_usec = tot_usec + basic_info_th->system_time.microseconds + basic_info_th->system_time.microseconds;
tot_cpu = tot_cpu + basic_info_th->cpu_usage / (float)TH_USAGE_SCALE * 100.0;
cpuDO.usage = basic_info_th->cpu_usage / (float)TH_USAGE_SCALE * 100.0;
if (container) {
[container addObject:cpuDO];
}
}
} // for each thread
複製代碼
  • iOS 內存獲取方式:測試過程當中使用的是phys_footprint,是最準確的物理內存,不少開源軟件用的是resident_size(這個值表明的是常駐內存,並不能很好地表現出真實內存變化,這能夠另開文章細談)
if ([[UIDevice currentDevice].systemVersion intValue] < 10) {
kern_return_t kr;
mach_msg_type_number_t info_count;
task_vm_info_data_t vm_info;
info_count = TASK_VM_INFO_COUNT;
kr = task_info(mach_task_self(), TASK_VM_INFO_PURGEABLE, (task_info_t)&vm_info,&info_count);
if (kr == KERN_SUCCESS) {
return (vm_size_t)(vm_info.internal + vm_info.compressed - vm_info.purgeable_volatile_pmap);
}
return 0;
}

task_vm_info_data_t vmInfo;
mach_msg_type_number_t count = TASK_VM_INFO_COUNT;
kern_return_t result = task_info(mach_task_self(), TASK_VM_INFO, (task_info_t) &vmInfo, &count);
if (result != KERN_SUCCESS)
return 0;
return (vm_size_t)vmInfo.phys_footprint;
複製代碼

聯繫咱們

若是對文本的內容有疑問或指正,歡迎告知咱們。

閒魚技術團隊是一隻短小精悍的工程技術團隊。咱們不只關注於業務問題的有效解決,同時咱們在推進打破技術棧分工限制(android/iOS/Html5/Server 編程模型和語言的統一)、計算機視覺技術在移動終端上的前沿實踐工做。做爲閒魚技術團隊的軟件工程師,您有機會去展現您全部的才能和勇氣,在整個產品的演進和用戶問題解決中證實技術發展是改變生活方式的動力。

簡歷投遞:guicai.gxy@alibaba-inc.com

相關文章
相關標籤/搜索