Android学习之性能工具traceView使用

【2016年3月30】

这几天分析一个滑动卡顿的问题,使用了traceView工具

问题点:

写邮件添加图片附件时,滑动编辑界面会出现卡顿现象,测试时发现只有特定图片才会卡顿

Android学习之性能工具traceView使用_第1张图片


1、打开DDMS,点击某一进程,点击Start Method Profiling,然后操作界面,再点击Stop Method Profiling,便会生出***.trace文件,包含时间轴和分析面板。

时间轴面板(Timeline Panel),包含这段时间内各个线程的执行,这里我截取了1840ms间的操作

Android学习之性能工具traceView使用_第2张图片


分析面板(Profile Panel)

Android学习之性能工具traceView使用_第3张图片


2、分析面板每一列的含义(来源互联网),默认按照Incl Cpu Time排列

列名

描述

Name

该线程运行过程中所调用的函数名

Incl Cpu Time

某函数占用的CPU时间,包含内部调用其它函数的CPU时间

Excl Cpu Time

某函数占用的CPU时间,但不含内部调用其它函数所占用的CPU时间

Incl Real Time

某函数运行的真实时间(以毫秒为单位),内含调用其它函数所占用的真实时间

Excl Real Time

某函数运行的真实时间(以毫秒为单位),不含调用其它函数所占用的真实时间

Call+Recur Calls/Total

某函数被调用次数以及递归调用占总调用次数的百分比

Cpu Time/Call

某函数调用CPU时间与调用次数的比。相当于该函数平均执行时间

Real Time/Call

CPU Time/Call类似,只不过统计单位换成了真实时间


3、分析过程

这里我点击Incl Real Time,按函数运行的真实时间排列,得出下图结果

Android学习之性能工具traceView使用_第4张图片

这里发现,滑动界面时,基本的耗时操作都在nSyncAndDrawFrame这个函数这里,为什么这样断定?因为我觉得1034.763ms和110.666ms这个时间间隔太大了,值得怀疑,于是点开这个函数,发现大部分时间都耗在context switch上

到这里没什么思路了,于是点击它的parent一级级找出它的调用栈

Android学习之性能工具traceView使用_第5张图片

看这个调用栈,搜了一下ThreadedRenderer,了解到这是一个android绘图的过程,看了一下ThreadedRenderer.java中draw的代码,这是一个同步过程,咨询了一下UI FW的同事,了解到nSyncAndDrawFrame会阻塞在这里,等待UI thread和RenderThread同步,如果APP有自己创建或者维护的bitmap时,RenderThread必须等Bitmap上传到GPU之后才会释放掉UI Thread, 如果APP没有提供或维护UI相关的Bitmap时, UI Thread不会阻塞,调用nSyncAndDrawFrame时瞬间就会返回。这里包含了一个重要信息,这个函数会阻塞UI thread,所以应该可以定位到是这里造成卡顿现象了。既然是bitmap相关的,这个滑动操作确实会把图片的缩略图显示出来,所以就去代码中寻找和bitmap相关的。


获取图片附件缩略图的代码是这样的

orgImage = MediaStore.Images.Thumbnails.getThumbnail(mContext.getContentResolver(), id, MediaStore.Images.Thumbnails.MINI_KIND, null);
                        
if(orgImage != null && degree != 0 ) {
    Matrix m = new Matrix();
    m.postRotate(degree);
    orgImage = Bitmap.createBitmap(orgImage, 0, 0, orgImage.getWidth(), orgImage.getHeight(), m, true);
}
return orgImage;


这里发现,直接获取图片后把根据orgImage的宽和高创建bitmap,单步调试到这里的时候,发现发生问题的bitmap的宽和高分别是4800和4233,天啊,这数据量也太大了,所以怀疑是图片数据太大导致RenderThread处理不过来,堵塞UI thread,从而造成卡顿,于是把代码改成下面这样,把宽和高按照需要显示的宽高等比例缩小

orgImage = MediaStore.Images.Thumbnails.getThumbnail(mContext.getContentResolver(), id, MediaStore.Images.Thumbnails.MINI_KIND, null);
Matrix matrix = new Matrix();
float scaleWidth  = ((float) width ) / orgImage.getWidth();
float scaleHeight = ((float) height ) / orgImage.getHeight();
matrix.postScale(scaleWidth, scaleHeight);
orgImage = Bitmap.createBitmap(orgImage, 0, 0, orgImage.getWidth(), orgImage.getHeight(), matrix, true);
                        
if(orgImage != null && degree != 0 ) {
    Matrix m = new Matrix();
    m.postRotate(degree);
    orgImage = Bitmap.createBitmap(orgImage, 0, 0, orgImage.getWidth(), orgImage.getHeight(), m, true);
}
return orgImage;


编出来一试,终于迎刃而解,几天下来的烦恼和压力也瞬间消失了,累觉不爱。
修改后,再抓一次traceView,发现RenderThread同步时花费的时间大大减少了

Android学习之性能工具traceView使用_第6张图片



【2016年4月7日】

这段时间公司在进行samsung app启动速度优化的工作,抓取了一下app启动时的traceView,根据Incl Cpu Time,发现启动过程有个地方消耗了200多毫秒,这对所有app都是额外的消耗

Android学习之性能工具traceView使用_第7张图片

根据parent和children的关系,找出这里的调用栈,如下

ActivityThread.parseCSCAppResource
ActivityThread.getCSCAppStringMap
ApplicationPackageManager.getCSCPackageItemText
ComponentInfo.loadLabel
ActivityThread.performLaunchActivity


查看ActivityThread.java的源码,最终parserCSCAppResource这个函数会去读取/system/csc/appresource/CSCAppResource.xml这个文件,文件操作会耗费大量时间,对于samsung app来说,启动应该是不需要读取运营商的内容的,所以这里去掉可对所有app的启动速度都能节省200多毫秒,最后交给app FW的同事去调查




你可能感兴趣的:(Android学习之性能工具traceView使用)