客户端native性能
目前我们性能方面主要关注的点帧率、CPU、内存、流量、图片、响应时间。以下对各点总结了下其标准、检验工具、问题排查。
一. 帧率
1. 标准:公司不同有可能不一致(屏蔽)
页面静默的时候GPU不应该再绘制(GPU呈现模式分析中没有图形变化)
2. 检验工具:自己公司开发的
3. 问题排查:
首先打开手机上“开发者选项里GPU呈现模式分析”查看什么操作下帧率绘制大于16ms,图形有三种颜色:蓝色、橙色、红色。蓝色表示测量绘制的时间;蓝色的线很高的时候,有可能是因为你的一堆视图突然变得无效了(即需要重新绘制),或者自定义视图的onDraw函数过于复杂。红色表示执行时间;红色的线非常高的时候,有可能自定义view比较复杂,嵌套多;另一种可能性是因为重新提交了视图而导致的。橙色表示处理时间;如果柱状图很高,那就意味着你给GPU太多的工作,太多的负责视图需要OpenGL命令去绘制和处理;也就是说view太多了。总结起来就是view太多,或者布局复杂太深,或者重新绘制没有复用(特别是有些可以复用的必然listview,gridview之类的)。其次就是打开“开发者选项里的GPU过度绘制”来查看究竟哪些view过度绘制了,有针对性的优化。布局优化了还有问题,那么影响帧率的因素还有:在启动activity或者fragment页面或者滑动页面的时候同时有多线程或者网络请求等待(traceview查看线程执行和耗时情况),或者有GC(trceview时,一般出现GC的时候时间线上会有比较大块的同颜色的区域点击后就可以定位到函数面板区域的GC函数一步一步向parent函数追踪就可以定位到GC的起因了),或者有重新绘制view的情况(在滑动过程中或者有动画的情况下做TraceView跟踪可以发现是否被触发了重新布局。在跟踪结束中搜索onLayout或者layout或者requestlayout可以方便找到对应的控件。)
6、动画或者滑动过程是否触发Layout
动画和滑动过程中在控件调用gone或者动态添加删除重新设置paramsTextView重新设置文字以及重新设置Drawable的时候都会触发Layout。在ListView的getview过程中它自己阻断了这个requestlayout自己对子控件做了layout的操作所以不会引起整个界面的重新布局。但是如果在其他时间设置了图片、文字等就可能导致requestlayout被触发进而执行onMeasure过程和onLayout过程这样的话就会大大影响了滑动过程中的性能容易造成卡顿。在滑动过程中或者有动画的情况下做TraceView跟踪可以发现是否被触发了重新布局。在跟踪结束中搜索onLayout或者layout或者requestlayout可以方便找到对应的控件。
9、查看布局性能问题
通过Incl Cpu Time百分比排序列表滑动过程中如果看到onMeasure或者onLayout大于25%以上的就应该可以判断出当前这个界面的布局性能不佳需要优化了。
在列表滑动过程中也需要检查getview这样的函数的性能特别是布局复杂的初始化时间会比较久。
10、查看布局复用问题
在列表滑动的过程中或者广告Banner控件一般的做法都是应该复用布局提升性能的但有时候因为觉得麻烦有些可能是动态添加的就没有复用这些view导致在滑动过程中还是会出现infalte布局的情况影响性能。跟踪方法是在这个列表已经滑动过的情况下开始进行TraceView这个时候来回滑动不应该出现infalte如果出现了就是复用出现了问题。如下跟踪发现有动态inflate button导致每次都额外增加了时间影响性能。
还有一种判断方法就是在进入界面的时候找出LayoutInflater.createViewFromTag函数找出它数量以及parents调用方检查是否有问题。
11、判断布局嵌套过多或者过于复杂
把Call+RecurCalls/Total和CpuTime/Call放到最前面通过View/ViewGroup的draw调用次数和递归调用次数来判断布局的层级过多或者布局Layout太多。也可以通过buildDisplayList函数的调用和递归调用次数来判断布局的层级过多或者是Layout太多。
二. CPU
1. 标准:CPU<75%,高CPU占用时间不能太长,具体按实际情况定;静默CPU<1%。
2. 检验工具:公司开发的,用android studio也可以看
3. 问题排查:
CPU突增,有可能是网络请求、复杂逻辑处理,具体情况要看这个时候的方法调用。高CPU占用时间长的,有可能方法自己处理占用时间长了,也有可能调用其他方法占用时间长,也有可能反复调用次数多了。这些具体情况可以用traceview工具查看(用debug包),在操作时,点击那个红点开始/结束(一般都是短时间的),之后看具体情况。
出现的图分上下两部分,上面部分可以直接看线程的执行时间长短,执行情况,下面是具体分析CPU使用时间和调用次数。首先是按照Incl Cpu Time查看占用时间长的,和哪些函数占用多,能找到具体方法。其次看Call+Recur Calls/Total(把Call+Recur Calls/Total和Cpu Time/Call放到最前面按照Call+Recur Calls/Total排序查看执行次数多的隐患函数展开其子函数分析是否存在问题并通过Incl Cpu Time的CPU占用比以及Incl Cpu Time的占用百分比来判断严重性特别是调用次数多的且Cpu Time/Call次数也多的应该重点排查。)
三. 内存
1. 标准:。内存不能一直往上升:native应该没什么变化(c内存的分配),dalvik在一个范围内波动(不能向上波动),不能波动太频繁(内存抖动:内存抖动是因为大量的对象被创建又在短时间内马上被释放。影响帧率),具体按实际情况定
2. 检验工具: 公司开发的,用android studio也可以看。
3. 问题排查:
内存抖动时一般是频繁GC,用Allocation Tracker来查看在短时间内分配的内存对象,找到这些元凶。Android Studio中的Memory Monitor也能查看程序的内存使用情况以及查看GC的情况。灰色部分为free,蓝色的为实际占用的。
内存泄露:内存增长的情况是存在没有被回收的情况,那么大部分是回收时被某个地方引用了,其生命周期更长。或者是无效的引用!
A.在DDMS中, 可以看到堆的大小和实际使用的大小,单一操作进行反复操作,在GC后,如果堆的大小一直增加,则有内存泄漏的隐患。
或者用adbshell dumpsys meminfo查看dalvik heap会不会持续增长。
B.利用在MAT分析dump hprof文件。
然后用MAT分析hprof文件(如果是现存文件了,不可读取时,还需要转换./hprof-conv 原文件目标文件)。
首先看overview中有没有明显的leak占用率和problem。
再是用Histogram查看,针对某个关键词搜索查看后按照objects或者retained heap排序后,右键list objects 可以查看被引用(incoming)或者引用。然后对这些引用可以右健 Path to GC Roots-->exclue all phantom/weak/soft etc. reference 查出某个实例没被释放的原因。用这个方法可以快速找到某个对象的 GC Root,一个存在 GC Root的对象是不会被GC回收掉的。
或者dominator Tree中按照Retained Memory排序,找出比较大的,然后用Path to GC Roots看看其引用情况。在这个Path中,一般会发现我们app自己包的类,可以分析这个类是不是还是需要的。如果不需要,那说明可能存在内存泄露。此时,在对这个自己包的类查看incoming references。看看到底是哪些引用导致它没有释放。
更多使用和查看原因可以网上查询MAT使用。
四. 流量
1. 标准:没有突增大的流量(一次请求页面突增大于2M时应该排查什么情况下产生,单个response数据返回最好不要超过50kb),没有重复请求 ;页面静默时或者处于后台(没有任何操作)不应该有流量增加了(有的话就要排查下什么再耗流量了)。这个size的限制主要考虑到非WiFi情况下耗流量和网络网速对数据传输的影响。
2. 检验工具:公司开发工具,抓包看数据请求,或者log查看是否有什么耗流量(比如默认上传数据,大量图片下载)
五.图片
1. 标准:网络请求图片<50kb;
2. 检验工具:直接抓包看下载下来的图片多大
六. 响应时间
1. 标准:activity响应时间<1s(原来的计算方法oncreate到onresume)-2s(从activiy的onCreate到layout的第五帧耗时)第二种方案:
以Activity onCreate为起点,页面检测到视图绘制5次后结束(通过监听DecorView PreDraw事件。onCreate是业务执行时间真正开始,在PreDraw 5次后视图框架基本已经加载完成。测试过程中发现,在第3次PreDraw之前,ActivityManagerDisplayed time已经计算出来,这也是为什么通过ActivityManager Displayedtime不能反映加载耗时原因,而Activity onCreate 到onResume的时间跟栅栏这两种方案,都只是ActivityManager Displayedtime过程的一部分
2. 源代码中埋点