移动性能测试 [转] 流言终结者- Flutter 和 RN 谁才是更好的跨端开发方案?

peter789 · 2018年09月10日 · 最后由 peter789 回复于 2018年09月16日 · 851 次阅读
本帖已被设为精华帖!

转自 https://mp.weixin.qq.com/s/XSfPs2hX2P7FPqRUyematA

背景

论坛上很多小伙伴关心为什么闲鱼选择了Flutter而不选择其他跨端方案?站在质量的角度,高性能是一个很重的因素,我们使用Flutter重写了宝贝详情页之后,对比了Flutter和Native详情页的性能表现,结论是中高端机型上Flutter和Native不相上下,在低端机型上,Flutter会比Native更加的流畅,其实闲鱼团队在使用Flutter做详情页过程中,没有更多地关注性能优化,为了更快地上线,也是优先功能的实现,不过测试结果出来之后,却出乎意料地优于原先的Native的实现(具体的测试结果,属于敏感数据,要走披露流程,伤不起…)

但是这样很显然不能敷衍过去,仔细想了想,确实Flutter的定位并不是要替代Native,他只想做一个极致的跨端解决方案,所以还是要回到跨端解决方案的赛道,给您从性能角度比一比,谁才是更好的跨端开发方案?

参赛选手

[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.

[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] https://github.com/CarGuo/GSYGithubAppFlutter
[REACT NATIVE] https://github.com/CarGuo/GSYGithubApp

场景

1、默认登录成功
2、“动态”页,点击搜索按钮,搜索关键字“Java”,正常速度浏览3页,等第4页加载完成后回退
3、点击“趋势”页Tab,浏览Feeds到页面底部,点击最底部的Item,进入Item后,浏览详情+浏览3页的动态后回退,到“我的”Tab页
4、查看“我的”Feeds到底部,点击右上角搜索按钮,搜索关键字“C”,浏览3页后,等第4页加载完成后场景结束

测试工具

  • 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

测试结论

1、Flutter在低端和中端的iOS机型上,FPS的表现都优于RN
2、CPU的使用上Flutter在低端机上表现略差于RN,中端机型略优于RN
3、值得注意的是内存上的表现(上图红色箭头区域),Flutter在低端机型上的起始内存和RN几乎一致,在中端机型上会多30M左右的内存(分析为Dart VM的内存),可以想到这应该是Flutter针对低端和中端机型上内存策略是不一样的,可用内存少的机型,Dart VM的初始内存少,运行时进行分配(这样也可以理解为什么在低端机上带来了更多的CPU损耗),中端机器上预分配了更多的VM内存,这样在处理时会更加的游刃有余,减少CPU的介入,带来更流畅的体验.
可以看出,Flutter团队在针对不同机型上处理更加的细腻,目的就是为了带来稳定流畅的体验。

Android

Xiaomi 2s 5.0.2

image.png

Sumsung S8 7.0

image.png

  • 注: MFS - Max Frame Space: 指的是去掉buffer之后的两帧的时间差

测试结论

1、Flutter在高低端机的CPU上的表现都优于RN,尤其在低端的小米2s上有着更优的表现
2、Android端在原来FPS基础上增加了流畅度的指标,FPS和流畅度的表现Flutter优于RN(计算规则见附参考文章)
3、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&流畅度: https://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];
}
}
}
  • 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;
共收到 10 条回复 时间 点赞

感谢分享,我们内部app最近都在用Flutter重写

oscarxie 回复

赞,后续可以交流flutter的测试,wigdet test和integration test 的玩法现在业界还是很少的

dart好用吗

今天按照flutter的教程进行的 编译运行阶段突然卡住了,截图如下

试了翻墙(翻墙的速度比较慢)也没有解决。

codeskyblue 回复

你这个看起来是gradle下载失败? 你可以用本地的gradle下一下,不要从网上下。
flutter程序根目录执行 flutter doctor 命令,发出来看看

peter789 回复
$ flutter doctor
Doctor summary (to see all details, run flutter doctor -v):
[] Flutter (Channel beta, v0.7.3, on Microsoft Windows [Version 10.0.16299.125], locale zh-CN)
[] Android toolchain - develop for Android devices (Android SDK 27.0.3)
[] Android Studio (version 3.1)
[] Connected devices (1 available)

No issues found!

本地的gradle该怎么弄,求指导

codeskyblue 回复

就是配置一个gradle的环境,然后配置gradle环境变量,在命令行直接gradle编译吧

仅楼主可见
Lihuazhang 将本帖设为了精华贴 09月15日 08:33
codeskyblue 回复


你是用Android studio 是吗? 在这边配置一下你本地下载好的

15922492150 回复

你可以问一下 浮云...
如果你可以在windows下可以用pycharm打开看一下 是不是 constants没有下载,是不是要 pip install constants,
不过还是建议你看一下 浮云实现的代码逻辑

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册