加入收藏 | 设为首页 | 会员中心 | 我要投稿 云计算网_宿迁站长网 (https://www.0527zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 运营中心 > 建站资源 > 网站推广 > 正文

手淘双十一521 性能优化项目揭秘

发布时间:2016-02-27 14:40:26 所属栏目:网站推广 来源:阿里百川专区的网站
导读:亿万用户都会在双十一这一天打开手机淘宝,高兴地在会场页面不断浏览,面对琳琅满目的商品图片,抢着添加购物车,下单付款。为了让用户更顺畅更方便地实现这一切,做到“如

各界面优化我们也是围绕着提高帧率和加快展现而展开的,手淘的几个主链路界面,都是相对比较复杂的,既使用多图,也使用了动态模板的技术。功能越复杂,也越容易产生性能问题,所以常遇到布局复杂、过渡绘制多、Activity主要函数耗时、内容展示慢、界面重新布局(Layout)、GC次数多等问题。

优化GPU的过渡绘制

通过开发者选项的GPU过渡绘制选项检查界面的过渡绘制情况。该优化并不复杂,通过去掉层叠布局中多余的背景设置、图片控件有前景内容的时候不显示背景、界面背景定义到Activity的主题中、减少Drawable的复杂Shape使用等手段就可以基本消除过渡绘制,减少对GPU和CPU的浪费。

优化层级和布局

层级越多,测量和布局的时间就会相应增加,创建硬件列表的时间也会相应增加。有时我们会嵌套很多布局来实现原本只要简单布局就可以实现的功能,有时还会添加一些测试阶段才会使用的布局。通过删除无用的层级,使用Merge标签或者ViewStub标签来优化整个布局性能。比如一些显示错误界面、加载提示框界面等,不是必须显示的这些布局可以使用ViewStub标签来提升性能。

另外要灵活使用布局,并不是层级越多就会性能越差,有时候1层的RelativeLayout会比3层嵌套的LinearLayout实现的性能更糟糕。

除了灵活使用布局,另外我们还通过提前inflate以及在线程中做一些必要的inflate等来提前初始化布局,减少实际显示时候的耗时。对于一些复杂的布局,我们还会自己做复用池,减少inflate带来的性能损耗,特别是在列表中。

加快界面显示

可以通过TraceView工具找出主线程的耗时操作和其他耗时的线程并作优化。另外减少主线程的GC停顿,因为即使并行GC,也会对heap加锁,如果主线程请求分配内存的话,也会被挂起,所以尽量避免在主线程分配较多对象和较大的对象,特别是在onDraw等函数中,以减少被挂起的时间。另外可以通过去掉ListView ,ScrollView等控件的EdgeEffect效果,来减少内存分配和加快控件的创建时间。

利用本地缓存,主要界面缓存上次的数据,并且配合增量的更新和删除,可以做到数据和服务端同步,这样可以直接展示本地数据,不用等到网络返回数据。

减少不必要的数据协议字段,减少名字长度等,并作压缩。还可以通过分页加载数据来加快传输解析时间。因为JSON越大,传输和解析时间也会越久,引发的内存对象分配也会越多。

注意线程的优先级,对于占用CPU较多时间的函数,也要判断线程的优先级。

优化动画细节

通过TraceView工具发现,一些Banner轮播广告和文字动画在移出可视区域后,仍然存在定时刷新,不仅耗电也影响帧率。优化措施是在移出可视区域后停止动画轮播。

阻断多余requestLayout

在ListView滑动,广告动画变化等过程中,图片和文字有变化,经常会发现整个界面被重新布局,影响了性能。尤其布局复杂时,测量过程很费时导致明显卡顿。对于大小基本固定的控件和布局例如TextView,ImageView来说,这是多余的损耗。我们可以用自定义控件来阻断,重写方法requestLayout、onSizeChanged,如果大小没有变化就阻断这次请求。对于ViewPager等广告条,可以设置缓存子view的数量为广告的数量。

优化中间件

中间件的代码被上层业务方调用的比较频繁,容易有较多的高频率函数,也容易产生细节上的问题。除了频繁分配对象外,例如类初始化性能,同步锁的额外开销,接口的调用时间,枚举的使用等等都是不能忽视的问题。

减少GC次数

安卓上的GC会引起性能卡顿,必须重点优化。除了第三章会详细介绍对于图片内存引起GC的优化,我们还做了如下工作:

减少对象分配,找出不必要的对象分配,如可以使用非包装类型的时候,使用了包装类型;字符串的+号和扩容;Handler.post(Runnable r)等频繁使用。

对象的复用,对于频繁分配的对象需要使用复用池。

尽早释放无用对象的引用,特别是大对象和集合对象,通过置为NULL,及时回收。

防止泄露,除了最基本的文件、流、数据库、网络访问等都要记得关闭以及unRegister自己注册的一些事件外,还要尽量少的使用静态变量和单例。

控制finalize方法的使用,在高频率函数中使用重写了finalize的类,会加重GC负担,使得性能上有几倍的差别。

合理选择容器,在性能上优先考虑数组,即使我们现在习惯了使用容器,也要注意频繁使用容器在性能上的隐患点:首先是扩容开销, HashMap扩容时重新Hash的开销较大。其次是内存开销,HashMap需要额外的Map.Entry对象分配 ,需要额外内存,也容易产生更多的内存碎片。SparseArray和ArrayList等在内存方面更有优势。再次是遍历,对于实现了RandomAccess接口的容器如ArryList的遍历,不应该使用foreach循环。

用工具监控和精雕细琢:在页面滑动过程中,通过Memory Monitor查看内存波动和GC情况,还可通过AlloCation Tracker工具观察内存的分配,发现很多小对象的分配问题。

利用Trace For OpenGL工具找出界面上导致硬件加速耗时的点,例如一些圆角图片的处理等。

通过多种工具和手段配合,手淘各个界面性能上有了较大的提高,平均帧率提高了20%,那么内存节省50%又是如何实现的哩,请看下文。

第三章 Android手机内存节省50%

Android上应用出现卡顿的核心原因之一是主线程完成绘制的周期过长引起丢帧。而影响主线程完成绘制时间的主要有两方面,一方面是主线程处于运行状态时需要做的任务太多但CPU资源有限,另外一方面是GC时Suspend时直接挂起了所有线程包括主线程。GC对总体性能的影响在4.x的系统上尤为突出,一部分是单次GC pause总时长,一部分是用户操作过程中GC发生的次数。而决定这两部分的因素就是Dalvik内存分配。那么在手淘这样的大型应用中到底是谁占用了内存大头呢?

谁占用了内存

基于双11前的手淘Android版本,我们在魅蓝note1(4.4 OS)上滑动完首页后,dump出其Dalvik Heap,整体内存占用的分布情况如下图。可以看出,byte数组(a)占用空间最大,绝大多数是用来存放Bitmap的像素数据(Pixel Data)。另外(c)与(d)一起占用了18.4%, byte数组加上Bitmap、BitmapDrawable总共占用了64.4%,成为内存占用的主体。

(编辑:云计算网_宿迁站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读