简介:满满干货

作者: 海潴,锦逸

随着闲鱼App端更多新功能、新技术的加入,应用冷启动速度越来越慢,这也意味着用户看到有效内容的时间被拉长,对用户体验有着很大的伤害。目前,在内部测试版本中,我们已经将Android的冷启动时间从原来的10s降低到了5s内。

闲鱼是如何快速将启动时间减少一半的呢?分为建立标准分析现状抓大放小三个步骤。

建立标准

做性能优化不是讨论哲学问题,建立合理的数据衡量标准非常重要。尽管已经有了很多关于如何卡口关键函数、如何判断页面第一帧渲染完成的讨论,但从代码层面进行判断始终与用户的感知无法100%得匹配。如何迅速建立起启动时间的标准?我们借鉴了手淘的方式和标准,利用内部的魔镜平台,使用视频关键帧的方式记录下App图标被点下到首页第一屏渲染完成作为一整个应用冷启动的过程。这与用户看到的启动过程吻合。

对于设备的选择上,我们使用y67这样一台现在看起来相对性能较差的机型作为优化的目标机型。低端机存在CPU能力弱,IO速度慢等问题,而慢代码与IO恰恰是拖慢应用启动最大的原因。定位优化的目标机型可以更加快速得解决common类型的启动问题。

闲鱼现状

我们先使用日志打点的方式来统计启动过程中耗时的大头,以便可以快速得将启动性能提高上去。可以看到图中,进入首页渲染前,commoninteractive两部分占去了大部分的时间,这是启动器在执行启动任务。而在进入首页后,页面的请求与view的排版占用了大部分的时间。

基于上面的分析,第一阶段我们将”启动任务治理“和”首页渲染加速“作为快速提升启动时间的重点来优化。

启动任务优化

闲鱼的Android端在16年的时候上线了一个基于DAG(有向无环图)的启动器,它将启动任务编排为一个DAG,并使用多核多线程并发的执行任务。上面说到的commoninteractive属于启动器执行任务的两个阶段,它们都会让主线程等待阶段中的任务全部执行完,所以这两个阶段的任务,我们叫它阻塞型任务

目前为止,整个闲鱼Android在启动阶段有77个任务需要执行,其中阻塞型任务有61个,y67上的总执行耗时在8s以上,并发后需要将近2.5s的时间。

对于启动阶段阻塞型任务,最快的优化方式有三点:

  1. 部分任务延迟执行
  2. 降低任务本身的耗时
  3. 拆分大任务

任务拆分与延迟执行

减少阻塞型任务的数量,是加速启动最直接的手段。这里需要根据任务的DAG进行依赖分析,能够无伤被延迟执行的任务最明显的特征就是”没有其他任务依赖于它“。如果任务之间有依赖,则需要根据后续首页对于模块的使用情况来决定是否将整个依赖链上的任务全部延迟。

闲鱼的首页金刚位大部分是weex、web和小程序的入口,另外首页也会用到端智能相关的功能。然而这四个sdk的初始化,普遍都在300-500ms左右,属于比较”硬核“任务。在将这四个任务移动到异步非阻塞阶段后,整个启动降低了500ms(当然要设置最高优先级以保证用户尽量少的等待时间)。

非阻塞任务的触发时机

任务启动的时机就像跟女生表白一样,不是你想启动,启动就启动的。错误的时机大概率造成灾难性得后果。

在我们将几个大任务移动到非阻塞阶段后发现,如果阶段启动的时候首页还没开始渲染或者没有渲染完成,整个首页的渲染会变得非常缓慢,图片的加载也随之变慢。总之就是谁碰到谁倒霉。实测中,非阻塞阶段启动的时机会对首页的渲染产生将近1s左右的波动,使得启动时间不断得在危险的边缘疯狂试探。

这是由于非阻塞阶段会在进入首页后的第一个queueIdle回调之后触发。而它的执行占用了多过的系统资源,造成CPU占用、网络请求排队、IO密集等问题。最终导致主线程、渲染变慢的情况。

那么什么时间才是启动非阻塞任务的合适时机呢?既然我们选择首页渲染为最高优先级,非阻塞任务的启动就必须排在后面。于是一咬牙一跺脚——”砍“!

我们让首页在确认view都上屏后,发信号给启动器。启动器这个时候才开始注册queueIdle回调,并启动一个延迟6s的runnable作为”备份“,防止message queue过忙长时间无法触发非阻塞阶段的任务。

但这里有个矛盾点,首页上几大金刚位都是通往weex、web或者小程序的,如果用户点击这些页面比非阻塞阶段的触发更早,该怎么办呢?当然是原谅触发它啊!

这里我们采用的方式是,当这些功能被触发的时候,需要先去check需要的模块是否已经初始化完成。如果没有的话,check非阻塞阶段是否已经启动。如果已启动,就进入等待,否则强制触发(这个时候首页必然已经渲染完成了),并等待所需要的任务执行完成。

任务耗时治理

要快速治理,需要利用一些成熟的工具。可以先对任务中的每一行代码进行时间统计,筛选出执行时间较长的调用后,使用系统提供的method trace进行更细粒度的分析。

既然是要快,那么一定是找通用类型的问题下手:

  • 对于IO出来的值,尽量做内存缓存,避免多次IO
  • 避免产生大的SharedPreference文件,尽可能得将对commit的调用换成apply
  • 注意一些异步接口回调的线程,如果是主线程,也需要保证回调后的代码快速执行完

首页启动优化

优化前,闲鱼的首页需要先进行三个排队的网络请求,弹出广告页,接着进行动态模板的渲染与数据绑定,总消耗时间在3.5s以上,这里面还不包括图片上屏的时间。

闲鱼首页部分的启动优化,主要也从三个方面来做:

  1. 广告页
  2. 数据预先加载
  3. View的预创建

广告页优化

闲鱼之前的广告页的流程如下图:

先拉起启动页,然后启动页拉起首页,首页再拉起广告页,广告页起来先展示默认图,然后同时去做是否有广告的判断,然后再去做广告的展示,这个过程如果没有广告,也会让默认的广告页展示3秒钟再关闭。

这个过程显然是不合理的,广告有自己的疲劳期,那么在没有广告的时候,拉起广告页就是一个浪费。其次广告页作为一个Activity拉起,需要经历一些IPC的调用,整个操作也是比较重的。

基于这两点,我们在广告页这块,先在初始化的时候就做提前的资源拉取和预判,这样如果确实没有广告资源,那么广告页直接不做启动,节省启动资源。其次,我们将广告页由一个activity,改造成一个全屏展示的Dialog,进一步来节省广告拉起时资源消耗,让首页其他内容的加载有更充足的系统资源。

数据预先加载

在性能优化中,空间换时间与提前预加载就像广为人知的”中间加一层“一样好用。

闲鱼首页必须的两个接口,冷启和热启接口耗时在1秒左右,而他们是在首页第一帧回调回来之后的时机才开始请求的。这里完全可以把请求的时机提前到初始化的过程中并行去做,从而为闲鱼启动-1s。

于是我们设计了针对这种情况下的预取模块,在初始化的时候,就去做首页数据的预加载,整体的模块的时序如下:

这一步做完之后,本地机器测试结果大约节约了950ms的启动时间。

View预创建

在解决完数据的问题之后,我们通过魔镜平台,会发现在y67上,首页展示之后,有大量的白屏的时间,view的创建和渲染,在这里消耗了大量资源,并占用了很长的时间(这里每一帧是100ms),平均大概在1400ms

于是我们自然而然的想到了在初始化的过程中去提前创建view,但是如果是在初始化过程中的主线程去创建view,那么势必会跟启动页和广告页等ui元素竞争主线程的使用,基本等于白干。

于是这里我们采用在子线程预先创建view并执行mesure与layout操作。等待首页渲染时,使用对应的id进行取出和使用。做完之后,会发现view的上屏时间,在y67上缩短到600ms,减少了一倍的的时间:

总结与下一步优化

通过上面的方式,整个启动阶段的时间从2.5s降低到了1.3s,降低了将近一倍的时间。另外启动任务所消耗的总时间从8s降低到了3s。首页的渲染几乎达到了秒出。整体启动时间降低到了4.5s左右。

这个阶段主要是对启动过程中的任务与首页代码本身的优化。下一阶段,我们会对整个启动过程中的运行环境进行优化:

  1. 对启动时候的资源消耗进行整理,减少不必要的网络请求与IO以及线程切换。
  2. 对启动器中的线程负载进行优化,目前启动的任务分配方式距离理论上的最优值(平均值)大约还有50%的空间。
  3. 使用dex-relayout、PGO加速启动

原文链接:https://developer.aliyun.com/article/770680?

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

闲鱼如何在2个月内实现Android启动速度翻倍的?相关推荐

  1. 闲鱼直播三周内实现点击率翻倍,我们是这么做到的...

    作者:闲鱼技术-莫癫 1. 业务背景 闲鱼直播业务上线后面临的最大问题是增长问题.闲鱼BI同学分析发现,对比短时观看和长时观看人群,发现两部分人群有较明显的兴趣阶段性差异. 业务希望在理解直播.主播和 ...

  2. 做短视频没有播放量?4个办法,1个月内让你粉丝翻倍

    做短视频没有播放量怎么办?有没有什么快速涨粉的办法?首先我们要知道,短视频没有播放量都有什么原因,总结一下,主要是视频的完播率,评论率,点赞率,转化率影响到播放量的.今天就给大家介绍4个办法,让你快速 ...

  3. 闲鱼自动刷新最新发布页面源码

    最近有个需求,就是快速的刷新界面,对某一个品,进行不断的刷新,去找到满意的品,进行捡漏. 当然具体的拍单没有写,大家直接看,写法很简单,直接操作就是了. var filepath = "/s ...

  4. 闲鱼研发框架应用和探索

    简介:Flutter是开源的UI工具包,其能够帮助开发者通过一套代码库高效构建多平台精美应用,支持移动.Web.桌面和嵌入式平台.在AliFlutter 系列第二场直播中,阿里巴巴闲鱼无线技术专家梁治 ...

  5. 对话阿里敏捷教练 | 成功辅导过淘宝、闲鱼,他都是如何帮助团队

    为了让大家对敏捷有更多的了解,小编特意采访了阿里巴巴高级技术专家.敏捷教练张燎原.他是如何看待敏捷.如何帮助团队落地敏捷的,作为研发团队的一员,我们可以从哪些地方着手敏捷,以下是对他的采访. 嘉宾简介 ...

  6. GMTC2019|闲鱼-基于Flutter的架构演进与创新

    2012年应届毕业加入阿里巴巴,主导了闲鱼基于Flutter的新混合架构,同时推进了Flutter在闲鱼各业务线的落地.未来将持续关注终端技术的演变及趋势 Flutter的优势与挑战 Flutter是 ...

  7. flutter 自定义键盘_掘金 AMA:听闲鱼客户端架构师邬吉风聊 Flutter 和移动端开发那些事...

    第二十一期 AMA 掘金团队请来了闲鱼客户端架构师,<Fish-Redux>作者-- 邬吉风做了为期三天的 Ask Me Anything (AMA) 活动(活动已结束).我们在此精选了一 ...

  8. 双十一的“后方战场”,闲鱼和转转吃饱了吗?

    今年的双十一格外不一样,之前口口声声消费自由.及时行乐的Z时代,清空购物车以后一个个化身"尾款人",纷纷吵着要"回血",由此也开辟了双十一之后的热门战场--二手 ...

  9. 掘金 AMA:听闲鱼客户端架构师--邬吉风聊 Flutter 和移动端开发那些事

    第二十一期 AMA 掘金团队请来了闲鱼客户端架构师,<Fish-Redux>作者-- 邬吉风做了为期三天的 Ask Me Anything (AMA) 活动(活动已结束). 我们在此精选了 ...

最新文章

  1. SQL查询不重复数据
  2. 微信小游戏开发教程-游戏实现3
  3. Django连接mysql数据库浅析
  4. 史上最简单的SpringCloud教程 | 第十篇: 高可用的服务注册中心
  5. oracle中lock和latch的用途
  6. 开源的DevOps开发工具箱
  7. 适用于应用程序错误的AWS警报
  8. TCP协议的三次握手和四次分手
  9. Jenkins Build Radiators(构建发射源)
  10. 黑客马拉松 招募_举办第一次黑客马拉松的提示
  11. 019,Intelidea右键新建选项没有Java class选项
  12. 架构师速成8.3-可用性之分库分表
  13. 信号报告(Java)
  14. c编程连接mysql
  15. scrollbar wpf 高度_Wpf ScrollBar自定义样式
  16. VM在使用过程中开机频繁黑屏(VM14版本问题导致的,频繁开机黑屏)
  17. 离线部署GitLab
  18. nginx 启动报错问题排查,和阿里云盾卸载方法
  19. 语音转文字软件哪个好,这三款值得收藏
  20. python文件审计_Python代码审计实战案例总结之CRLF和任意文件读取

热门文章

  1. mysql 5.7版本目录无data文件夹的解决办法
  2. 分析数据时,一定要避开这5大误区!
  3. 记一次 Python Web 接口优化,性能提升25倍!
  4. 支持中文的算法可视化网站,你想要的算法这都有
  5. 全选文字的快捷键_高效办公必备Excel快捷键之Ctrl+26个字母!掌握它们,告别加班...
  6. python使用redis在实际场景使用_Python使用Redis实现作业调度系统(超简单)
  7. win oracle 重启命令,Windows下命令行如何启动Oracle10g?
  8. angularjs ajax header,angularJs/ajax跨域请求携带cookies
  9. 牛客练习赛38 E 出题人的数组 2018ccpc桂林A题 贪心
  10. python安装第三方库