Network monitor
最后更新于:2022-04-01 22:54:42
# Network monitor工具能做什么?
实时监控上传和接收的网速
# Network monitor使用条件
* root手机
* Android studio 1.4+
# Network monitor开启
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d376df5c.jpg)
Tx:上传网速
Rx:接受网速
';
Android性能专项测试之GPU Monitor
最后更新于:2022-04-01 22:54:40
> [Testing Display Performance](https://developer.android.com/intl/zh-cn/training/testing/performance.html#timing-dump)
> [Speed up your app](http://blog.udinic.com/2015/09/15/speed-up-your-app?from=timeline&isappinstalled=0)
# GPU Monitor能做什么?
分析GPU的性能,实时查看绘制每一帧所花费的时间
# GPU Monitor使用准备
* root 手机
* 开发者选项中的Gpu profile开关打开
* Android Studio 1.4+
# GPU Monitor启动
在Android Monitor中点击GPU,就已经打开了该工具,这个时候你在所选App界面中操作的话,面板中就会实时显示绘制数据:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d374112c.jpg)
# GPU Monitor的4类数据
5.1之前的数据只有蓝,红,黄三种颜色,5.1加入了紫色数据
## Draw(蓝)
表示View.onDraw()方法的耗时,这部分主要是建立DisplayList对象用的,这些对象将会被转化成OpenGL命令,GPU只能读懂OpenGL命令。
如果这个地方耗时比较大,说明视图比较复杂。
蓝色区域代表的时间,是创建DisplayList对象的时间。
## Prepare(紫色)
5.1以后将UI Thread线程所做的事分成了2个线程来做:UI Thread和Render Thread。新加的Render Thread线程会将Draw过程生成的DisplayList对象转化成为OpenGL的命令,然后发送给GPU,这个时候UI Thread可以空闲下来处理下一个frame的数据。如果传送的资源过多的话这个地方耗时就比较大。
紫色区域代表的时间就是UI Thread传送数据给Render Thread所用的时间。
## Process(红)
红色区域代表创建OpenGL命令的时间
## Execute(黄)
黄色区域代表发送OpenGL命令给GPU所用的时间
';
Systrace工具
最后更新于:2022-04-01 22:54:38
> [Systrace Walkthrough](https://developer.android.com/intl/zh-cn/tools/performance/systrace/index.html)
> [Systrace](http://developer.android.com/intl/zh-cn/tools/help/systrace.html#options)
> [Analyzing UI Performance with Systrace](http://developer.android.com/intl/zh-cn/tools/debugging/systrace.html#app-trace)
> [Speed up your app](http://blog.udinic.com/2015/09/15/speed-up-your-app?from=timeline&isappinstalled=0)
# Systrace能做什么?
* 计算容器的性能
* 发现性能的瓶颈
# Systrace的使用准备
* 4.1以上
* root
* Android SDK Tools 20
* python环境
# Systrace启动
你可以通过命令行或者Device Monitor两种方式收集Systrace信息,以下以命令行为例介绍收集方式(因为我Device Monitor的方式报错)。
首先进入sdk下的platform-tools/systrace目录下:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d354432b.jpg)
然后在命令下执行以下命令来收集数据:
`python systrace.py --time=10 -o mynewtrace.html sched gfx view wm`
上面的参数–time为间隔时间,-o为文件名,更详细的参数信息如下:
| 参数名 | 意义 |
| --- | --- |
| `-h,--help` | 帮助信息 |
| `-o ` | 保存的文件名 |
| `-t N,--time=N` | 多少秒内的数据,默认为5秒,以当前时间点往后倒N个时间 |
| `-b N,--buf-size=N` | 单位为千字节,限制数据大小 |
| `-k --ktrace=` | 追踪特殊的方法 |
| `-l,--list-categories` | 设置追踪的标签 |
| `-a ,--app=` | 包名 |
| `--from-file=` | 创建报告的来源trace文件 |
| `-e ,--serial=` | 设备号 |
其中标签可选项如下:
| 标签名 | 意义 |
| --- | --- |
| gfx | Graphics |
| input | Input |
| view | View |
| webview | Webview |
| vm | Window Manager |
| am | Activity Manager |
| audio | Audio |
| video | Video |
| camera | Camera |
| hal | Hardware Modules |
| res | Resource Loading |
| dalvik | Dalvik VM |
| rs | RenderScript |
| sched | Cpu Scheduling |
| freq | Cpu Frequency |
| membus | Memory Bus Utilization |
| idle | Cpu Idle |
| disk | Disk input and output |
| load | Cpu Load |
| sync | Synchronization Manager |
| workq | Kernel Workqueues |
以上标签并不支持所有机型,还有要想在输出中看到任务的名称,需要加上sched.
上面的命令执行完后,会生成一个html文件:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d356992a.jpg)
打开该文件后,我们会看到如下页面:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d35c7d9b.jpg)
# systrace快捷键
| 快捷键 | 作用 |
| --- | --- |
| w | 放大 |
| s | 缩小 |
| a | 左移 |
| d | 右移 |
| f | 返回选中区域,切放大选中区域 |
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d3606c69.jpg)
# Alerts
Alerts一栏标记了以下性能有问题的点,你可以点击该点查看详细信息,右边侧边栏还有一个Alerts框,点击可以查看每个类型的Alerts的数量:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d3674b15.jpg)
# Frame
在每个包下都有Frame一栏,该栏中都有一个一个的`F`代表每一个`Frame`,用颜色来代表性能的好坏,依次为`绿-黄-红`(性能越来越差),点击某一个`F`,会显示该Frame绘制过程中的一些Alerts信息:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d36c6c64.jpg)
如果你想查看Frame的耗时,可以点击某个F标志,然后按`m`键:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d3718f7f.jpg)
';
Android性能专项测试之MAT
最后更新于:2022-04-01 22:54:36
> 参考文章:
> [Android内存优化之二:MAT使用进阶](http://ju.outofmemory.cn/entry/172685)
> [Android内存优化之一:MAT使用入门](http://ju.outofmemory.cn/entry/172684)
> [MAT中的Bitmap图像 ](http://androidperformance.com/2015/04/11/AndroidMemory-Open-Bitmap-Object-In-MAT/)
> [10 Tips for using the Eclipse Memory Analyzer](http://eclipsesource.com/blogs/2013/01/21/10-tips-for-using-the-eclipse-memory-analyzer/)
# MAT使用
MAT工具全称为Memory Analyzer Tool,一款详细分析Java堆内存的工具,该工具非常强大,为了使用该工具,我们需要hprof文件,该文件我们在之前的[Heap Snapshot工具](http://blog.csdn.net/itfootball/article/details/48786275)的时候,我们就生成了该文件。但是该文件不能直接被MAT使用,需要进行一步转化,可以使用hprof-conv命令来转化,但是Android Studio可以直接转化,转化方法如下:
1.选择一个hprof文件,点击右键选择`Export to standard .hprof`选项。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d326f6de.jpg)
2.填写更改后的文件名和路径:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d32a01c9.jpg)
点击OK按钮后,MAT工具所需的文件就生成了,下面我们用MAT来打开该工具:
1.打开MAT后选择`File->Open File`选择我们刚才生成的doctorq.hprof文件
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d32d8312.jpg)
2.选择该文件后,MAT会有几秒种的时间解析该文件,有的hprof文件可能过大,会有更长的时间解析,解析后,展现在我们的面前的界面如下:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d32f2dc2.jpg)
这是个总览界面,会大体给出一些分析后初步的结论
# Overview视图
该视图会首页总结出当前这个Heap dump占用了多大的内存,其中涉及的类有多少,对象有多少,类加载器,如果有没有回收的对象,会有一个连接,可以直接参看(图中的Unreachable Objects Histogram)。
比如该例子中显示了Heap dump占用了41M的内存,5400个类,96700个对象,6个类加载器。
然后还会有各种分类信息:
## Biggest Objects by Retained Size
会列举出Retained Size值最大的几个值,你可以将鼠标放到饼图中的扇叶上,可以在右侧看出详细信息:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d3319e1e.jpg)
图中灰色区域,并不是我们需要关心的,他是除了大内存对象外的其他对象,我们需要关心的就是图中彩色区域,比如图中2.4M的对象,我们来看看该对象到底是啥:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d33539fa.jpg)
该对象是一个Bitmap对象,你如果想知道该对象到底是什么图片,可以使用图片工具gimp工具浏览该对象.
##
# histogram视图
histogram视图主要是查看某个类的实例个数,比如我们在检查内存泄漏时候,要判断是否频繁创建了对象,就可以来看对象的个数来看。也可以通过排序看出占用内存大的对象:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d337bfb4.jpg)
默认是类名形式展示,你也可以选择不同的显示方式,有以下四种方式:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d33a7d4f.jpg)
下面来演示一下:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d33cfe82.jpg)
# Dominator tree视图
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d344fe0a.jpg)
该视图会以占用总内存的百分比来列举所有实例对象,注意这个地方是对象而不是类了,这个视图是用来发现大内存对象的。这些对象都可以展开查看更详细的信息,可以看到该对象内部包含的对象:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d3488cba.jpg)
# Leaks suspects视图
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d34be793.jpg)
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d34d6ac2.jpg)
这个视图会展示一些可能的内存泄漏的点,比如上图上图显示有3个内存泄漏可疑点,我们以`Problem Suspect 1`为例来理解该报告,首先我们来看该可疑点详细信息:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d3505b98.jpg)
上面信息显示`ImageCahe`类的一个实例`0xa50819f8`占用了14.19%的内存,具体值为5147200字节(5147200/1024/1024=4.9M),并存放在LinkedHashMap这个集合中,然后我们点击Details跳转到更详细的页面:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d3522708.jpg)
这样我们就能找到在我们的app源码中造成该泄漏可疑点的地方,很容易去定位问题.
';
TraceView工具(Device Monitor)
最后更新于:2022-04-01 22:54:33
> 参考文章: [Traceview Walkthrough](https://developer.android.com/intl/zh-cn/tools/performance/traceview/index.html)
> [Android 编程下的 TraceView 简介及其案例实战](http://www.cnblogs.com/sunzn/p/3192231.html)
> [正确使用Android性能分析工具——TraceView](http://blog.jobbole.com/78995/)
> [Android内存使用分析和程序性能分析](http://liaohuqiu.net/cn/posts/memory-and-profile-analysis-in-android/)
# TraceView工具能做什么?
从代码层面分析性能问题,针对每个方法来分析,比如当我们发现我们的应用出现卡顿的时候,我们可以来分析出现卡顿时在方法的调用上有没有很耗时的操作,关注以下两个问题:
* 调用次数不多,但是每一次执行都很耗时
* 方法耗时不大,但是调用次数太多
简单一点来说就是我们能找到频繁被调用的方法,也能找到执行非常耗时的方法,前者可能会造成Cpu频繁调用,手机发烫的问题,后者就是卡顿的问题
# TraceView工具启动
打开Monitor,点击图中的标注的按钮,启动追踪:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d306f7eb.jpg)
# TraceView工具面板
打开App操作你的应用后,再次点击的话就停止追踪并且自动打开traceview分析面板:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d308e384.jpg)
traceview的面板分上下两个部分:
* 时间线面板以每个线程为一行,右边是该线程在整个过程中方法执行的情况
* 分析面板是以表格的形式展示所有线程的方法的各项指标
## 时间线面板
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d30ca62b.jpg)
左边是线程信息,main线程就是Android应用的主线程,这个线程是都会有的,其他的线程可能因操作不同而发生改变.每个线程的右边对应的是该线程中每个方法的执行信息,左边为第一个方法执行开始,最右边为最后一个方法执行结束,其中的每一个小立柱就代表一次方法的调用,你可以把鼠标放到立柱上,就会显示该方法调用的详细信息:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d30e5067.jpg)
你可以随意滑动你的鼠标,滑倒哪里,左上角就会显示该方法调用的信息。
1.如果你想在分析面板中详细查看该方法,可以双击该立柱,分析面板自动跳转到该方法:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d3112b91.jpg)
2.放大某个区域
刚打开的面板中,是我们采集信息的总览,但是一些局部的细节我们看不太清,没关系,该工具支持我们放大某个特殊的时间段:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d313ecd4.jpg)
如果想回到最初的状态,双击时间线就可以。
3.每一个方法的表示:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d3184189.jpg)
可以看出来,每一个方法都是用一个`凹`型结构来表示,坐标的凸起部分表示方法的开始,右边的凸起部分表示方法的结束,中间的直线表示方法的持续.
## 分析面板
面板列名含义如下:
| 名称 | 意义 |
| --- | --- |
| Name | 方法的详细信息,包括包名和参数信息 |
| Incl Cpu Time | Cpu执行该方法该方法及其子方法所花费的时间 |
| Incl Cpu Time % | Cpu执行该方法该方法及其子方法所花费占Cpu总执行时间的百分比 |
| Excl Cpu Time | Cpu执行该方法所话费的时间 |
| Excl Cpu Time % | Cpu执行该方法所话费的时间占Cpu总时间的百分比 |
| Incl Real Time | 该方法及其子方法执行所话费的实际时间,从执行该方法到结束一共花了多少时间 |
| Incl Real Time % | 上述时间占总的运行时间的百分比 |
| Excl Real Time % | 该方法自身的实际允许时间 |
| Excl Real Time | 上述时间占总的允许时间的百分比 |
| Calls+Recur | 调用次数+递归次数,只在方法中显示,在子展开后的父类和子类方法这一栏被下面的数据代替 |
| Calls/Total | 调用次数和总次数的占比 |
| Cpu Time/Call | Cpu执行时间和调用次数的百分比,代表该函数消耗cpu的平均时间 |
| Real Time/Call | 实际时间于调用次数的百分比,该表该函数平均执行时间 |
你可以点击某个函数展开更详细的信息:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d31c0199.jpg)
展开后,大多数有以下两个类别:
* Parents:调用该方法的父类方法
* Children:该方法调用的子类方法
如果该方法含有递归调用,可能还会多出两个类别:
* Parents while recursive:递归调用时所涉及的父类方法
* Children while recursive:递归调用时所涉及的子类方法
首先我们来看当前方法的信息:
| 列 | 值 |
| --- | --- |
| Name | 24 android/widget/FrameLayout.draw(L android/graphics/Canvas;)V |
| Incl Cpu% | 20.9% |
| Incl Cpu Time | 375.201 |
| Excl Cpu Time % | 0.0% |
| Excl Cpu Time | 0.000 |
| Incl Real Time % | 1.1% |
| Incl Real Time | 580.668 |
| Excl Real Time % | 0.0% |
| Excl Real Time | 0.000 |
| Calls+Recur | 177+354 |
| Cpu Time/Call | 0.707 |
| Real Time/Call | 1.094 |
根据下图中的toplevel可以看出总的cpu执行时间为1797.167ms,当前方法占用cpu的时间为375.201,375.201/1797.167=0.2087,和我们的Incl Cpu Time%是吻合的。当前方法消耗的时间为580.668,而toplevel的时间为53844.141ms,580.668/53844.141=1.07%,和Incl Real Time %也是吻合的。在来看调用次数为177,递归次数为354,和为177+354=531,375.201/531 = 0.7065和Cpu Time/Call也是吻合的,580.668/531=1.0935,和Real Time/Call一栏也是吻合的。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d31e82dd.jpg)
### Parents
现在我们来看该方法的Parents一栏:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d320ab62.jpg)
| 列 | 值 |
| --- | --- |
| Name | 22 com/android/internal/policy/impl/PhoneWindow$DecorView.draw(Landroid/graphics/Canvas;)V |
| Incl Cpu% | 100% |
| Incl Cpu Time | 375.201 |
| Excl Cpu Time % | 无 |
| Excl Cpu Time | 无 |
| Incl Real Time % | 100% |
| Incl Real Time | 580.668 |
| Excl Real Time % | 无 |
| Excl Real Time | 无 |
| Call/Total | 177/531 |
| Cpu Time/Call | 无 |
| Real Time/Call | 无 |
其中的Incl Cpu Time%变成了100%,因为在这个地方,总时间为当前方法的执行时间,这个时候的Incl Cpu Time%只是计算该方法调用的总时间中被各父类方法调用的时间占比,比如Parents有2个父类方法,那就能看出每个父类方法调用该方法的时间分布。因为我们父类只有一个,所以肯定是100%,Incl Real Time一栏也是一样的,重点是Call/Total,之前我们看当前方式时,这一栏的列名为Call+Recur,而现在变成了Call/Total,这个里面的数值变成了177/531,因为总次数为531次,父类调用了177次,其他531次是递归调用。这一数据能得到的信息是,当前方法被调用了多少次,其中有多少次是父类方法调用的。
### Children
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d322cb8e.jpg)
可以看出来,我们的子类有2个,一个是自身,一个是`23android/view/View.draw(L android/graphics/Canvas;)V`,self代表自身方法中的语句执行情况,由上面可以看出来,该方法没有多余语句,直接调用了其子类方法。另外一个子类方法,可以看出被当前方法调用了177次,但是该方法被其他方法调用过,因为他的总调用次数为892次,你可以点击进入子类方法的详细信息中。
### Parents while recursive
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d323cb66.jpg)
列举了递归调用当前方法的父类方法,以及其递归次数的占比,犹豫我们当前的方法递归了354次,以上三个父类方法递归的次数分别为348+4+2 = 354次。
### Children while recursive
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d3255424.jpg)
列举了当递归调用时调用的子类方法。
';
Heap Snapshot工具
最后更新于:2022-04-01 22:54:31
> [Speed up your app](http://blog.udinic.com/2015/09/15/speed-up-your-app?from=timeline&isappinstalled=0)
# Heap Snapshot能做什么?
获取Java堆内存详细信息,可以分析出内存泄漏的问题
# Heap Dump启动
![这里写图片描述](http://img.blog.csdn.net/20150928165053130)
在内存面包中,点击图中红色标注的按钮,就会显示我们的Heap Snapshot面包
# Heap Snapshot面板
![这里写图片描述](http://img.blog.csdn.net/20150928170254721)
# Heap Snapshot详细信息面板
![这里写图片描述](http://img.blog.csdn.net/20150928171540998)
该面板里的信息可以有三种类型:app heap/image heap/zygote heap.
分别代表app 堆内存信息,图片堆内存信息,zygote进程的堆内存信息。
## A区域
列举了堆内存中所有的类,一下是列表中列名:
| 名称 | 意义 |
| --- | --- |
| Total Count | 内存中该类的对象个数 |
| Heap Count | 堆内存中该类的对象个数 |
| Sizeof | 物理大小 |
| Shallow size | 该对象本身占有内存大小 |
| Retained Size | 释放该对象后,节省的内存大小 |
## B区域
当我们点击某个类时,右边的B区域会显示该类的实例化对象,这里面会显示有多少个实体,以及详细信息。
| 名称 | 意义 |
| --- | --- |
| depth | 深度 |
| Shallow Size | 对象本身内存大小 |
| Dominating Size | 管辖的内存大小 |
当你点击某个对象时,将展开该对象内部含有哪些对象,同时C区域也会显示哪些对象引用了该对象:
![这里写图片描述](http://img.blog.csdn.net/20150928224240950)
## C区域
![这里写图片描述](http://img.blog.csdn.net/20150928224746908)的某对象引用树对象,在这里面能看出其没谁引用了,比如在内存泄漏中,可以看出来它被谁引用,比如上图,引用树的第一行,可以看出来,该对象被Object[12]对象引用,索引值为1,那我们展开后,可以看到,该Object[12]是一个ArrayList.
![这里写图片描述](http://img.blog.csdn.net/20150928224836618)
# Android studio1.4的更新
1.4的面板有一些变化:
![这里写图片描述](http://img.blog.csdn.net/20151009171948678)
较之前添加了一个数据显示方式的选择,可以选择类名排列或者包名排列:
![这里写图片描述](http://img.blog.csdn.net/20151009172334227)
';
Allocation Tracker(Android Studio)
最后更新于:2022-04-01 22:54:29
> [Speed up your app](http://blog.udinic.com/2015/09/15/speed-up-your-app?from=timeline&isappinstalled=0)
# Android Studio版的特点
Allocation Tracker(AS)工具比Allocation Tracker(Eclipse)工具强大的地方是更炫酷,更清晰,但是能做的事情都是一样的。
# Allocation Tracker启动
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d2bf2a2f.jpg)
在内存图中点击途中标红的部分,启动追踪,再次点击就是停止追踪,随后自动生成一个alloc结尾的文件,这个文件就记录了这次追踪到的所有数据,然后会在右上角打开一个数据面板:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d2c1fd9f.jpg)
面板左上角是所有历史数据文件列表,后面是详细信息,好,现在我们来看详细介绍信息面板:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d2c4afef.jpg)
下面我们用字母来分段介绍
## A:查看方式选项
A标识的是一个选择框,有2个选项
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d2c6a943.jpg)
* Group by Method:用方法来分类我们的内存分配
* Group by Allocator:用内存分配器来分类我们的内存分配
不同的选项,在D区显示的信息会不同,默认会以Group by Method来组织,我们来看看详细信息:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d2c83b2a.jpg)
从上图可以看出,首先以线程对象分类,默认以分配顺序来排序,当然你可以更改,只需在Size上点击一下就会倒序,如果以Count排序也是一样,Size就是内存大小,Count就是分配了多少次内存,点击一下线程就会查看每个线程里所有分配内存的方法,并且可以一步一步迭代到最底部:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d2c9d939.jpg)
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d2cc4710.jpg)
当你以Group by Allocator来查看内存分配的情况时,详细信息区域就会变成如下:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d2cf20b1.jpg)
默认还是以内存分配顺序来排序,但是是以每个分配者第一次分配内存的顺序:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d2d167b6.jpg)
这种方式显示的好处,是我们很好的定位我们自己的代码的分析信息,比如上图中,以包名来找到我们的程序,在这次追踪中包民根目录一共有五个类作为分配器分配了78-4-1=73次内存。
## B:Jump To Source按钮
如果我们想看内存分配的实际在源码中发生的地方,可以选择需要跳转的对象,点击该按钮就能发现我们的源码,但是前提是你有源码:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d2d167b6.jpg)
如果你能跳转到源码,Jump To Source按钮才是可用的,都是跳转到类。
## C:统计图标按钮
该按钮比较酷炫,如果点击该按钮,会弹出一个新窗口,里面是一个酷炫的统计图标,有柱状图和轮胎图两种图形可供选择,默认是轮胎图,其中分配比例可以选择分配次数和占用内存大小,默认是大小Size
## 轮胎图
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d2d4f3d6.jpg)
轮胎图是以圆心为起点,最外层是其内存实际分配的对象,每一个同心圆可能被分割成多个部分,代表了其不同的子孙,每一个同心圆代表他的一个后代,每个分割的部分代表了某一带人有多人,你双击某个同心圆中某个分割的部分,会变成以你点击的那一代为圆心再向外展开。如果想回到原始状态,双击圆心就可以了。
1.起点
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d2d7990f.jpg)
圆心是我们的起点处,如果你把鼠标放到我图中标注的区域,会在右边显示当前指示的是什么线程(Thread1)以及具体信息(分配了8821次,分配了564.18k的内存),但是红框标注的区域并不代表Thread1,而是第一个同心圆中占比最大的那个线程,所以我们现在把鼠标放到第一个同心圆上,可以看出来,我们划过同心圆的轨迹时可以看到右边的树枝变化了好几个值:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d2da7d6c.jpg)
2.查看某一个扇面
我们刚打开是全局信息,我们如果想看其中某个线程,详细信息,可以顺着某个扇面向外围滑动,当然如果你觉得不还是不清晰,可以双击该扇面全面展现该扇面的信息:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d2e2f1eb.jpg)
在某个地方双击时,新的轮胎图是以双击点为圆心,你如果想到刚才的圆,双击圆心空白处就可以:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d2e8d9ad.jpg)
3.一个内存的完整路径
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d2ee1d7f.jpg)
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d2f1b0f1.jpg)
## 柱状图:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d2f7b49c.jpg)
柱状图以左边为起始点,从左到右的顺序是某个的堆栈信息顺序,纵坐标上的宽度是以其Count/Size的大小决定的。柱状图的内容其实和轮胎图没什么特别的地方
1.起点
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d2fadbd1.jpg)
2.查看某一个分支
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d2fe7e19.jpg)
3.Count/Size切换
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d3035985.jpg)
';
Allocation Tracker(Device Monitor)
最后更新于:2022-04-01 22:54:27
> [Allocation Tracker Walkthrough](https://developer.android.com/intl/zh-cn/tools/performance/allocation-tracker/index.html)
# Allocation Tracker 能做什么?
追踪内存分配信息,按顺序排列,这样我们就能清晰看出来某一个操作的内存是如何一步一步分配出来的。比如在有内存抖动的可疑点,我们可以通过查看其内存分配轨迹来看短时间内有多少相同或相似的对象被创建,进一步找出发生问题的代码。
# Allocation Tracker使用条件
* Root手机
* 开发者选项可用
# Allocation Tracker面板
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d2ab732a.jpg)
各名称的含义如下:
| 名称 | 意义 |
| --- | --- |
| Alloc Order | 分配序列 |
| Allocation Size | 分配的大小 |
| Allocated Class | 被分配的对象 |
| Thread Id | 线程id号 |
| Allocated in | 在哪个类分配的 |
| 第二个Allocated in | 在哪个方法分配的 |
# Allocation Tracker操作
1.首先进入你要追踪的界面
2.点击`Start Tracking`按钮,开始跟踪内存分配轨迹
3.操作你的界面,尽量时间短点
4.点击`Get Allocations`按钮,抓去内存分配轨迹信息,显示在右边的面板中,默认以内存大小排序,你可以以分配顺序排序或者仍以列排序。
5.logcat中会显示出这次的轨迹共抓到内存分配轨迹记录数,可以简单的理解分配了多少次内存,这个数值和Alloc order的最大值是相等的
6.如果你不想看那么多乱七八糟的,你可以使用Filter来过滤,输入包名就可以了。
# 实例
## 无任何操作时内存轨迹
打开首页,点击`Stop tracking`,然后点击`Get Allocations`,会看到下面1~8的内存分配序列:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d2af0619.jpg)
再按一次`Get Allocations`会出现如下状态:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d2b16320.jpg)
这些信息估计都是DDMS和app交互产生的内存,我们可以忽略
## 正常操作的内存轨迹
如果这个时候我们想单独获取某次操作的内存轨迹,首先一定要记得`Stop Tracking`再`Start Tracking`一下,让追踪点初始化一下,这个时候我们从首页进入一个详情页,看一下我们的内存分配轨迹:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d2b38ad7.jpg)
追踪到的内存分配3823次,看着是不是有点无从下手,没关系,用Filter过滤下:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d2b6c893.jpg)
过滤后,就剩下了跟我们App源码有关系的分配轨迹,我们随便选择一栏,可以看到其trace信息:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d2bb6eb4.jpg)
上图中,我们可以看出来,在第2415次内存分配中,分配的是`DetailFragment`对象,占用内存272字节,处理线程Id为1,在`com.example.android.sunshine.app.DetailActivity`的`onCreate`方法中分配的。从trace信息可以看出来该方法一步一步被调用的信息。
然后我们回源码中确认下,以下代码就是我们上面选择的内存分配的地方:
~~~
private final String LOG_TAG = DetailActivity.class.getSimpleName();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail);
Log.d(LOG_TAG, "onCreate");
ActivityManager.getInstance().registerActivity(this);
if (savedInstanceState == null) {
// Create the detail fragment and add it to the activity
// using a fragment transaction.
Bundle arguments = new Bundle();
arguments.putParcelable(DetailFragment.DETAIL_URI, getIntent().getData());
DetailFragment fragment = new DetailFragment();
fragment.setArguments(arguments);
getSupportFragmentManager().beginTransaction()
.add(R.id.weather_detail_container, fragment)
.commit();
}
}
~~~
';
Heap Viewer工具
最后更新于:2022-04-01 22:54:24
> 参考文章:[Heap Viewer](https://developer.android.com/intl/zh-cn/tools/performance/heap-viewer/index.html)
> [Android 内存监测工具 DDMS –> Heap ](http://blog.csdn.net/feng88724/article/details/6460918)
> [使用DDMS中的内存监测工具Heap来优化内存](http://www.cnblogs.com/tianzhijiexian/p/4267919.html)
# Heap Viewer能做什么?
* 实时查看App分配的内存大小和空闲内存大小
* 发现Memory Leaks
# Heap Viewer使用条件
* 5.0以上的系统,包括5.0
* 开发者选项可用
# Heap Viewer启动
可以直接在Android studio工具栏中直接点击小机器人启动:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d294e19b.jpg)
还可以在Android studio的菜单栏中Tools也可以:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d29677b1.jpg)
如果你不用Android studio,可以在SDK下的tools下的monitor程序打开:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d2995fa0.png)
# Heap Viewer面板
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d29c548d.jpg)
按上图的标记顺序按下,我们就能看到内存的具体数据,右边面板中数值会在每次GC时发生改变,包括App自动触发或者你来手动触发。
ok,现在来解释下面板中的名词
## 总览
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d2a0515f.jpg)
| 列名 | 意义 |
| --- | --- |
| Heap Size | 堆栈分配给App的内存大小 |
| Allocated | 已分配使用的内存大小 |
| Free | 空闲的内存大小 |
| %Used | Allocated/Heap Size,使用率 |
| Objects | 对象数量 |
## 详情
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d2a1c51a.jpg)
| 类型 | 意义 |
| --- | --- |
| free | 空闲的对象 |
| data object | 数据对象,类类型对象,最主要的观察对象 |
| class object | 类类型的引用对象 |
| 1-byte array(byte[],boolean[]) | 一个字节的数组对象 |
| 2-byte array(short[],char[]) | 两个字节的数组对象 |
| 4-byte array(long[],double[]) | 4个字节的数组对象 |
| non-Java object | 非Java对象 |
**下面是每一个对象都有的列名含义:**
| 列名 | 意义 |
| --- | --- |
| Count | 数量 |
| Total Size | 总共占用的内存大小 |
| Smallest | 将对象占用内存的大小从小往大排,排在第一个的对象占用内存大小 |
| Largest | 将对象占用内存的大小从小往大排,排在最后一个的对象占用的内存大小 |
| Median | 将对象占用内存的大小从小往大排,拍在中间的对象占用的内存大小 |
| Average | 平均值 |
当我们点击某一行时,可以看到如下的柱状图:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d2a41dff.jpg)
横坐标是对象的内存大小,这些值随着不同对象是不同的,纵坐标是在某个内存大小上的对象的数量
# Heap Viewer的使用
我们说Heap Viewer适合发现内存泄漏的问题,那你知道何为内存泄漏么?
## 内存泄漏
英文名:Memory Leaks
标准解释:无用的单纯,但是还是没GC ROOT引用的内存
通俗解释:该死不死的内存
## 检测
那么如何检测呢?Heap Viewer中的数值会自动在每次发生GC时会自动更新,那么我们是等着他自己GC么?小弟不才,刚开始我就是这么一直等啊等,由于GC的时机是系统把握的,所以很不好把握,既然我们是来看内存泄漏,那么我们在需要检测内存泄漏的用例执行过后,手动GC下,然后观察`data object`一栏的`total size`(也可以观察Heap Size/Allocated内存的情况),看看内存是不是会回到一个稳定值,多次操作后,只要内存是稳定在某个值,那么说明没有内存溢出的,如果发现内存在每次GC后,都在增长,不管是慢增长还是快速增长,都说明有内存泄漏的可能性。
## 实例
先来看3个图:
1.刚打开首页,手动GC一下:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d2a59014.jpg)
2.首页到详情页10遍,最后回到首页,手动GC一下,直到数值不再变化:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d2a7735c.jpg)
3.首页到详情页10遍,最后回到首页,手动GC一下:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d2a93a6a.jpg)
从`data object`一栏看到该类型的数值会在不断增长,可能发生了内存泄漏,而我们也可以从上面三个图的标红部分来看,Allocated分别增加了`2.418M`和`1.084M`,而且你继续这么操作下去,内存依然是增长的趋势
# 补充
Heap Viewer不光可以用来检测是否有内存泄漏,对于内存抖动,我们也可以用该工具检测,因为内存抖动的时候,会频繁发生GC,这个时候我们只需要开启Heap Viewer,观察数据的变化,如果发生内存抖动,会观察到数据在段时间内频繁更新。
';
Memory Monitor工具
最后更新于:2022-04-01 22:54:22
> 参考文章:
> [Memory Monitor Walkthrough](http://developer.android.com/intl/zh-cn/tools/performance/memory-monitor/index.html)
# Memory Monitor能做什么?
* 实时查看App的内存分配情况
* 快速判断App是否由于GC操作造成卡顿
* 快速判断App的Crash是否是因为超出了内存
# Memory Monitor使用准备
* 开发者选项可用
* USB调试开启
备注:Android Studio的`Enable ADB Integration`勾选(Tools/Android下)。
# Memory Monitor面板
首先执行`adb devices`来确保设备可用,然后启动`Android Studio`,选择一个Android项目或者新建一个项目进入主面板,如果你有你的待测App的源码,那么最好进入你自己的App项目中,这样方便调试和定位问题。进入项目后,可以看到Android Studio的主面板左下角有一个`Android`标签:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d28ca513.jpg)
点击该标签打开`Android`面板,如下图所示:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d290469c.jpg)
A:设备选择
B:可监控的App选择
C:内存的实时数据
重点来看C区域,横坐标记录从采集开始点到目前已经过去的时间,纵坐标是分配给App使用的内存总量[Allocated+Free],蓝色区域表示已分配[Allocated]使用的的,灰色区域表示空闲[Free]未使用的。在坐标轴的右边可以看见具体数值。
## GC
GC就是垃圾回收的意思,我们可以从Memory monitor看到何时发生了GC event,当一个内存短时间内发生掉落,我们可以认为发生了GC操作。你也可以手动触发GC,下图中的小车子就是触发GC的按钮,一旦按下就会回收那些没被引用的对象(这个地方不能说没用的对象,因为没用的对象有可能是内存泄漏时的对象,后期会来研究):
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d2922d32.jpg)
# Memory Monitor可以发现的问题
Memory Monitor工具为监控工具,是一种发现型或者说监控性质的工具,比如医生的四大技能[望闻问切],[望]是第一步。这里的Memory Monitor就是一种[望]的工具,目前我主要用它来看下面几个内存问题:
1.发现内存抖动的场景
2.发现大内存对象分配的场景
3.发现内存不断增长的场景
4.确定卡顿问题是否因为执行了GC操作
# 案例分析
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d2938f05.jpg)
上面的第一段标记显示内存突然增加了7M,我们也能看的很清楚,所以这个点我们要去定位了一下问题在哪里,是Bitmap还是什么原因造成的,第二段标记是内存抖动,很明显在很短的时间了发生了多次的内存分配和释放。而且在发生内存抖动的时候,也能感觉到App的卡顿,可以看出来是由于执行了GC操作造成的。
内存的不断增加通过Memory monitor很容易看出来,蓝色的曲线是一路高歌猛进的,一看便知。
# 关于内存泄漏的问题
Memory Monitor也可以归纳到用于检测内存泄漏的工具,但是我没这么做,因为在实际过程中,当泄漏的点每一次很小的时候,你很难发现,没有Heap Viewer好使。如果泄漏的对象占用内存大的话,也能通过Memory Monitor看出来。
';
battery-historian试用
最后更新于:2022-04-01 22:54:20
# 数据准备
battery-historian工具需要使用bugreport中的Battery History
数据,我们在开始的时候需要通过以下命令来打开电池数据的获取以及重置:
~~~
adb shell dumpsys batterystats --enable full-wake-history
shell dumpsys batterystats --reset
~~~
执行的效果如下:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d2602c12.jpg)
上面的操作相当于初始化操作,现在做一些测试,手动或者跑一些自动化的case都行。经过一段时间后,我们运行下面两条命令来将bugreport的信息保存到txt文档中,然后将txt文档转化为html文件。
~~~
adb bugreport > bugreport.txt
python historian.py -a bugreport.txt > battery.html
~~~
上面的historian.py脚本是python写的,所以需要python环境,然后从[github](https://github.com/google/battery-historian)上下载这个脚本。上面两条命令执行成功后,会在目录下发现两个文件
bugreport.txt和battery.html,这个时候我们用google浏览器打开html文件,可以看到如下信息:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d289027d.jpg)
# 各个参数的意义
首先我们在bugreport.txt找到Battery History数据栏类似下面的信息:
~~~
-------------------------------------------------------------------------------
DUMP OF SERVICE batterystats:
Battery History (2% used, 5980 used of 256KB, 45 strings using 2592):
0 (9) RESET:TIME: 2015-03-05-15-21-56
0 (2) 100 c0900422 status=discharging health=good plug=none temp=200 volt=4167 +running +wake_lock +sensor +screen data_conn=edge phone_signal_strength=great brightness=medium proc=u0a15:"android.process.acore"
0 (2) 100 c0900422 proc=u0a7:"com.android.cellbroadcastreceiver"
0 (2) 100 c0900422 proc=u0a53:"com.android.gallery3d"
~~~
你在html中信息都能从bugreport.txt中找到相应的信息。
现在来分析各个指标代表的意义:
# 横坐标
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d28a749a.jpg)
上面的10,20代表的就是秒的意思,它是以一分钟为周期,到第60秒的时候变为0。横坐标就是一个时间范围,咱们的例子中统计的数据是以重置为起点,获取bugreport内容时刻为终点。我们一共采集了多长时间的数据,图表下也有信息说明。(经其他人的反馈,这个坐标间隔是会随着时间的长度发生改变,所以要以你的实际情况为准)
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2015-12-31_56849d28b4287.jpg)
# 纵坐标
纵坐标的数据就很麻烦了,数据量太多,一条一条来吧。
## battery_level
电量,可以看出电量的变化。比如上图中的数据显示刚开始电量是100%,然后在第11秒-12秒中间的某个时刻降到了99%。
## plugged
充电状态,这一栏显示是否进行了充电,以及充电的时间范围。例如上图反映了我们在第22s插入了数据线,然后一直持续了数据采集结束。
## screen
屏幕是否点亮,这一点可以考虑到睡眠状态和点亮状态下电量的使用信息。
## top
该栏显示当前时刻哪个app处于最上层,就是当前手机运行的app,用来判断某个app对手机电量的影响,这样也能判断出该app的耗电量信息。该栏记录了应用在某一个时刻启动,以及运行的时间,这对我们比对不同应用对性能的影响有很大的帮助。
## wake_lock*
[wake_lock](http://blog.csdn.net/g_salamander/article/details/7978772) 该属性是记录wake_lock模块的工作时间。是否有停止的时候等
## running
界面的状态,主要判断是否处于idle的状态。用来判断无操作状态下电量的消耗。
## wake_lock_in
wake_lock有不同的组件,这个地方记录在某一个时刻,有哪些部件开始工作,以及工作的时间。
## data_conn
数据连接方式的改变,上面的edge是说明采用的gprs的方式连接网络的。此数据可以看出手机是使用2g,3g,4g还是wifi进行数据交换的。这一栏可以看出不同的连接方式对电量使用的影响。
## status
电池状态信息,有充电,放电,未充电,已充满,未知等不同状态。
这一栏记录了电池状态的改变信息。
## phone_signal_strength
手机信号状态的改变。
这一栏记录手机信号的强弱变化图,依次来判断手机信号对电量的影响。
## health
电池健康状态的信息,这个信息一定程度上反映了这块电池使用了多长时间。
这一栏记录电池状态在何时发生改变,上面的图中电池状态一直处于good状态。
## plug
充电方式,usb或者插座,以及显示连接的时间。
这一栏显示了不同的充电方式对电量使用的影响。
';
前言
最后更新于:2022-04-01 22:54:17
> 原文出处:[Android性能专项测试专栏文章](http://blog.csdn.net/column/details/itfootballprefermanc.html)
> 作者:[钱辉](http://blog.csdn.net/itfootball)
**本系列文章经作者授权在看云整理发布,未经作者允许,请勿转载!**
# Android性能专项测试
> Android性能测试专题
';