本文主要介绍Android性能调优工具TraceView的使用及通过其确定性能点。
目前性能优化专题已完成以下部分:
性能优化第三篇——Java(Android)代码优化
性能优化第二篇——布局优化
性能优化第一篇——数据库性能优化
Android自带的TraceView堪比java的性能调优工具visualvm线程视图,可以方便的查看线程的执行情况,某个方法执行时间、调用次数、在总体中的占比等,从而定位性能点。
1、生成日志,运行TraceView
运行TraceView有两种方式
a、调用Debug类
在开始调试的地方,如Activity的onCreate函数,添加
1 |
Debug.startMethodTracing("tracefilename"); |
结束调试的地方,如Activity的onDestroy函数,添加
1 |
Debug.stopMethodTracing(); |
之后运行你的app一段时间并退出会在sd卡根目录生成tracefilename.trace这个log文件,记录这段时间内的运行信息。
将日志文件pull到PC端,cmd到android sdk tools文件夹内(或绑定sdk tools目录到系统path内),运行traceview tracefilename.trace即可打开TraceView分析界面,如下
这种方式可以随意开始和结束调试的位置,所以适合具体代码的性能排查。find貌似只支持小写,所以如果查找JsonObject需要输入jsonobject
b、使用DDMs
打开devices窗口,选择某个进程,点击右上角的start method profiling
运行app一段时间后,再点击已变成stop method profiling的该按钮。eclipse会自动弹出debug的标签(可通过菜单File->save as保存数据)。界面同上面。
这种方式不需要修改代码,所以对于没有源码的程序同样可以进行排查。同时可以方便的进行全局性能排查。
2、TraceView界面信息介绍
TraceView界面包括时间面板和方法面板
(1) 时间面板(Timeline Panel)
时间面板展示了每个线程的执行情况,其中的[1]main即为ui主线程。
移动到某个位置可以查看该点对应的方法的执行信息,点击方法面板则会选中相应的方法。
可以左键按住不放选中区域放大局部精细查看,不同方法用不同颜色标注
(2) 方法面板(Profile Panel)
方法面板展示了所有方法的执行情况,点击某个方法可以查看在对应线程上的执行时间区域,并会显示其父方法及子方法。
每个方法包括如下信息列,可点击某列进行排序,从而确定产生性能问题的函数:
Incl Cpu Time, Excl Cpu Time, Incl Real Time, Excl Real Time, Incl Cpu Time%, Excl Cpu Time%, Incl Real Time%, Excl Real Time%, Calls+RecurCalls/Total, Cpu Time/Call, Real Time/Call
所有的Time都是以毫秒计算。每列具体含义及作用如下:
a. Incl表示将所有子函数耗时也计算在内,Excl则表示不包括子函数的调用时间。对比可以确定耗时操作发生是自身还是子函数中。
b. Cpu Time表示占用cpu执行的时间,Real Time包括Cpu Time以及等待、切换的时间等,所以一般都大于Cpu Time。对比可以判断耗时操作是否在cpu执行段内。
c. 上面四个指标对应的%表示函数在总时间的占比。方便查看某个函数的时间占比。
d. Calls+RecurCalls/Total表示被外部调用次数+递归次数/总次数。可以查看调用次数是否符合自己预期。
e. Cpu Time/Call, Real Time/Call表示总的Cpu Time及Real Time与总调用次数的比例。查看每次调用的耗时,一般可通过简单此项确定每个函数的性能。
3、其他调优工具
(1) dmtracedump
sdk tools下的另外一个工具dmtracedump可用于生成上述log文件内的函数调用关系图,不过在windows上稍微大点的文件即或报错
(2) visualvm
看到ddms提供了dump hprof file的功能,本来准备生成hprof文件用visualvm打开试试,结果一直打不开..
在银狐的帮忙下,发现android sdk tools dump的hprof需要经过sdk tools下的hprof-conv转换为标准的hprof文件,才能通过visualvm或eclipse的MemoryAnalyzer打开进行分析,之后就同java一样了。hprof-conv格式为
hprof-conv <infile> <outfile>
关于visualvm可以简单的查看http://trinea.iteye.com/blog/1216170
之后会写篇文章详细的介绍visualvm和MemoryAnalyzer
性能调优工具,学习了。
请教,mac下定位到traceview文件的位置,却无法调用。tools下的其它文件也是无法调用,不知为何?
不好意思,一直在windows下面工作,这个问题你还是google吧
不错
我现在遇到一个问题,在给listview增加下拉刷新的时候,本来不卡的列表,一旦下拉刷新的View出现的屏幕中,就卡的不行,log不停的在打GC回收内存,TraceView我也看不懂,就是看到好像onMeasure不不停的调用。而且不像是下拉刷新的ListVIew写的有问题,因为这个控件在其他地方用的很好,没出过这个问题。而我的列表本身也不卡。就是组合起来的时候,一旦拉下刷新的HeadView出现在屏幕中,就开始奇卡无比,一旦消失,就恢复,快崩溃了。。
你测试下是不是下拉刷新的HeadView出现在屏幕中就会卡,而不管列表是什么。还有你用的下拉刷新是自己写的还是哪个开源提供的
是HeadView出现就会卡,消失就不会卡。但是这个List控件在其他地方用起来没有出现问题。我试过两个List控件了,都会卡。一个是eoe客户端开源代码中的,一个团队一直用的。
这里有一个下拉刷新ListView的demo,我测试了headView显示不会卡。里面有示例apk和google code地址,你可以先看看示例apk,满足的话从google code拉下代码,把DropDownListViewDemo的mStrings变量改成只有几个值,让headview显示看看效果
感谢之前给我推荐下拉刷新的控件。现在定位到是ViewPager的问题,可能是占用内存过多造成的,因为代码问题没有有效利用资源。我现在ViewPager,有3个page,每个page里放一个Fragment,存放一个ListVIew。请教下ViewPager或者PageAdapter应该如何优化呢?也可能是我的调用方式不对。。另外求Android方面的书籍,我想是时候补补钙了。。
不好意思,前段时间一直在休假,根据你提供的布局情况应该还是java代码的问题,内错过多一般不会导致程序缓慢,除非多到系统内存都不足了。
ViewPager有个setOffscreenPageLimit控制page缓存个数,我开到了最大性能也没啥问题。
性能优化的书你可以参考这本书,Android应用性能优化 ,讲的不错
不好意思,前段时间一直在休假,根据你提供的布局情况应该还是java代码的问题,内错过多一般不会导致程序缓慢,除非多到系统内存都不足了。ViewPager有个setOffscreenPageLimit控制page缓存个数,我开到了最大性能也没啥问题。性能优化的书你可以参考这本书,Android应用性能优化 ,讲的不错
你这个评论插件好厉害,打开chrome就弹出提示信息了。只不过每次回复都新开一条,有点混乱。你真够厉害,我后来已经发现,及时不用ViewPager,单独一个列表都会卡顿了,只不过正在改其他东西,优化放在了后面。肯定是我Java本身的水平太差了,还不清楚哪里出的问题呢。总之就是见到log不停的在打GC_CONCURRENT书我记下了,回头一定去看看!
嘿嘿,这个插件是多说评论,现在很多网站都在用,样式也不错就选了,不足的地方也不少就像你说的那点。打印GC_CONCURRENT说明有类似循环的操作不停分配对象导致dalvik不停的做gc回收
详细来说,是给我那个列表加入上拉下拉回弹效果的时候,就比如带回弹效果的下拉刷新,一旦拉出HeadView,就开始卡顿,gc不停地回收。我也没什么经验,准备用笨办法,先从逻辑上确定几个可能点,然后逐一注释掉,看看影响。
如果是加上下拉效果就会有问题,你把那个逻辑二份注释排查就可以了
有个疑问,局部变量中加final修饰符,会保证只初始化一次吗?
该函数多次执行还是会重新初始化的,只能保证在该函数的一次调用中不会被再次赋值
我看网上有个版本的ListView优化里,在Adapter的getView函数中,每次convertView == null的时候,new一个新的LayoutInflater。与持有一个成员变量相比,两者区别大吗?我知道Adapter里inflate与findViewById是耗时最长的
不用每次new LayoutInflater, 这种会更损失性能,不过LayoutInflater对象不大,所以也不会太大影响。这里有提到ListView getView比较好的写法
感谢,总之尽量少new对象,比如需要多次使用并且可复用的对象,比如LayoutInflater这种,改为持有一个全局变量,只创建一次比较好是不是。
嗯,尽量减少对象的创建是没错的,尤其是new很费时但又使用频繁的对象。这种也不叫全局变量,只是对局部变量来说,局部范围从方法扩展到了类。
笔误笔误,是成员变量对吧=。=
嗯嗯
性能调优工具,学习了。
dump出的prof文件需要用sdk tools下hprof-conv转换之后才能被其他工具打开
非常感谢^_^#,我试了下确实可以
最新版直接安装Eclipse MAT插件就能用啊,不需要转来转去。试用了一下TraceView,貌似还不错。
在新版的DDMS中TraceView可以直接在Eclipse中运行,不过跟你说的mat还不一样。mat侧重内存分析,常用于Java内存泄漏排查,android的oom也可以dump后用它查看。而TraceView可方便的查看方法运行时间及线程运行状况多用于性能调优,类似java的visualvm和jprofile的部分功能
恩。明白了。顺便问一下,如果当前程序已经发生了OOM,而且“成功”的挂掉了,能否通过Dump文件来查看OOM?而不是通过Logcat。
我一般先看/data/system/dropbox这个目录下的system_app_crash@xxxxx.txt日志文件,这个文件已经能说明fc的原因了。你说的运行中保存hprof我看stackoverflow也有解决方案an Android process produce a heap dump on an OutOfMemoryError
自己制造了一个OOM,去/data/system/dropbox找了下,system_app_crash@xxxxx.txt没看到,倒是看到了一其它的,如:SYSTEM_BOOT@xxx.txt,system_app_strictmode@xxx.txt,event_data@xxx.txt,不知道是不是android版本的问题。我使用 是Android 3.0.1。其它机器都是非工程机,看不了dropbox。第说的第二个方法应该是可行的。
我这边偶尔fc的日志也是看不到的,但概率比较小。SYSTEM_BOOT@xxx.txt是启动日志,system_app_strictmode@xxx.txt是严格模式(设置-开发者选项中)的日志,这个下面还有一个比较有用的就是system_app_anr@xxx.txt表示某个时间点应用anr日志