Android性能分析工具

来源:互联网 发布:ubuntu下安装windows 编辑:程序博客网 时间:2024/05/16 07:34

这里写图片描述

DDMS

DDMS 的全称是Dalvik Debug Monitor Service,是Android 开发环境中的Dalvik 虚拟机调试监控服务

这里写图片描述

这里写图片描述

HierarchyViewer

UI性能分析工具,分析布局文件的性能,层级嵌套

UI布局复杂程度及冗余分析,View嵌套的冗余层级

View的性能指标:测量、布局、绘制的渲染时间

1、invalidate Layout按钮

invalidate(),强制刷新

2、requestLayout按钮

requestLayout(),重新测量,布局

使用GPU过度绘制分析UI性能

开发者选项中的GPU过度绘制工具(Show GPU Overdraw)

这里写图片描述

使用GPU呈现模式图及FPS考核UI性能

开发者选项中的GPU呈现模式分析,Profile GPU Rendering

这里写图片描述

Android Monitor

这里写图片描述

这里写图片描述

TraceView

TraceView 简介

Traceview 是Android 平台特有的数据采集和分析工具,它主要用于分析Android 中应用程序的hotspot(瓶颈)。Traceview 本身只是一个数据分析工具,而数据的采集则需要使用Android SDK 中的Debug 类或者利用DDMS 工具。二者的用法如下:

开发者在一些关键代码段开始前调用Android SDK 中Debug 类的startMethodTracing 函数,并在关键代码段结束前调用stopMethodTracing 函数。这两个函数运行过程中将采集运行时间内该应用所有线程(注意,只能是Java线程)的函数执行情况,并将采集数据保存到/mnt/sdcard/下的一个文件中。开发者然后需要利用SDK 中的Traceview工具来分析这些数据。

借助Android SDK 中的DDMS 工具。DDMS 可采集系统中某个正在运行的进程的函数调用信息。对开发者而言,此方法适用于没有目标应用源代码的情况。DDMS 工具中Traceview 的使用如下图所示。

观察CPU的执行情况,测试的进程中每个线程运行的时间线,线程中各个方法的调用信息(CPU使用时间、调用次数等)

可以方便的查看线程的执行情况,某个方法执行时间、调用次数、在总体中的占比等,从而定位性能点

一般Traceview可以定位两类性能问题

  • 方法调运一次需要耗费很长时间导致卡顿
  • 方法调运一次耗时不长,但被频繁调运导致累计时长卡顿

这里写图片描述

这里写图片描述

这里写图片描述

这里写图片描述

点击上图中所示按钮即可以采集目标进程的数据。当停止采集时,DDMS 会自动触发Traceview 工具来浏览采集数据

下面,我们通过一个示例程序介绍Traceview 的使用。

实例程序如下图所示:界面有4 个按钮,对应四个方法。

这里写图片描述

点击不同的方法会进行不同的耗时操作。

public class MainActivity extends ActionBarActivity {        @Override        protected void onCreate(Bundle savedInstanceState) {            super.onCreate(savedInstanceState);            setContentView(R.layout.activity_main);        }        public void method1(View view) {            int result = jisuan();            System.out.println(result);        }        private int jisuan() {            for (int i = 0; i < 10000; i++) {                System.out.println(i);            }            return 1;        }        public void method2(View view) {            SystemClock.sleep(2000);        }        public void method3(View view) {            int sum = 0;            for (int i = 0; i < 1000; i++) {                sum += i;            }            System.out.println("sum=" + sum);        }        public void method4(View view) {            Toast.makeText(this, "" + new Date(), 0).show();        }    }

我们分别点击按钮一次,要求找出最耗时的方法。点击前通过DDMS 启动Start Method Profiling 按钮。
这里写图片描述

然后依次点击4 个按钮,都执行后再次点击上图中红框中按钮,停止收集数据。

接下来我们开始对数据进行分析。

当我们停止收集数据的时候会出现如下分析图表。该图表分为2 大部分,上面分不同的行,每一行代表一个线程的执行耗时情况。main 线程对应行的的内容非常丰富,而其他线程在这段时间内干得工作则要少得多。图表的下半部分是具体的每个方法执行的时间情况。显示方法执行情况的前提是先选中某个线程。

这里写图片描述

我们主要是分析main 线程。

上面方法指标参数所代表的意思如下:

列名 描述 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 类似,只不过统计单位换成了真实时间

 
我们为了找到最耗时的操作,那么可以通过点击Incl Cpu Time,让其按照时间的倒序排列。我点击后效果如下图:

这里写图片描述

通过分析发现:method1 最耗时,耗时2338 毫秒。

这里写图片描述

那么有了上面的信息我们可以进入我们的method1 方法查看分析我们的代码了

生成.trace文件

android.os.Debug类,其中重要的两个方法Debug.startMethodTracing()和Debug.stopMethodTracing()。这两个方法用来创建.trace文件,将从Debug.startMethodTracing()开始,到Debug.stopMethodTracing()结束,期间所有的调用过程保存在.trace文件中,包括调用的函数名称和执行的时间等信息。

这里写图片描述

这里写图片描述

dmtracedump

dmtracedump -g result.png target.trace  //结果png文件  目标trace文件

Allocation Tracker

追踪内存的分配,追踪内存对象的来源,通过这个工具我们可以很方便的知道代码分配了哪类对象、在哪个线程、哪个类、哪个文件的哪一行

运行DDMS,只需简单的选择应用进程并单击Allocation tracker 标签,就会打开一个新的窗口,单击“Start Tracing”按钮;

然后,让应用运行你想分析的代码。运行完毕后,单击“Get Allocations”按钮,一个已分配对象的列表就会出现第一个表格中。

单击第一个表格中的任何一项,在表格二中就会出现导致该内存分配的栈跟踪信息。通过allocation tracker,不仅知道分配了哪类对象,还可以知道在哪个线程、哪个类、哪个文件的哪一行。

这里写图片描述

Systrace

这里写图片描述
Systrace其实有些类似Traceview,它是对整个系统进行分析

DDMS->Capture system wide trace using Android systrace

Heap

这里写图片描述

内存监测工具,分析内存使用情况,查看当前内存快照,便于对比分析哪些对象有可能是泄漏了的

heap 工具可以帮助我们检查代码中是否存在会造成内存泄漏的地方。用heap 监测应用进程使用内存情况的步骤如下:

  • 启动eclipse 后,切换到DDMS 透视图,并确认Devices 视图、Heap 视图都是打开的

  • 点击选中想要监测的进程,比如system_process 进程;

  • 点击选中Devices 视图界面中最上方一排图标中的“Update Heap”图标;

  • 点击Heap 视图中的“Cause GC”按钮;

  • 此时在Heap 视图中就会看到当前选中的进程的内存使用量的详细情况。

说明:

  • 点击“Cause GC”按钮相当于向虚拟机请求了一次gc 操作;

  • 当内存使用信息第一次显示以后,无须再不断的点击“Cause GC”,Heap 视图界面会定时刷新,在对应用的不断的操作过程中就可以看到内存使用的变化;

  • 内存使用信息的各项参数根据名称即可知道其意思,在此不再赘述。

如何才能知道我们的程序是否有内存泄漏的可能性呢。这里需要注意一个值:Heap 视图中部有一个Type叫做data object,即数据对象,也就是我们的程序中大量存在的类类型的对象。在data object 一行中有一列是“Total Size”,其值就是当前进程中所有Java 数据对象的内存总量,一般情况下,这个值的大小决定了是否会有内存泄漏。可以这样判断:

  • 不断的操作当前应用,同时注意观察data object 的Total Size 值

  • 正常情况下Total Size 值都会稳定在一个有限的范围内,也就是说由于程序中的的代码良好,没有造成对象不被垃圾回收的情况,所以说虽然我们不断的操作会不断的生成很多对象,而在虚拟机不断的进行GC 的过程中,这些对象都被回收了,内存占用量会会落到一个稳定的水平;

  • 反之如果代码中存在没有释放对象引用的情况,则data object 的Total Size 值在每次GC 后不会有明显的回落,随着操作次数的增多Total Size 的值会越来越大,直到到达一个上限后导致进程被kill 掉

  • 此处以system_process 进程为例,在我的测试环境中system_process 进程所占用的内存的data object
    的Total Size 正常情况下会稳定在2.2~2.8 之间,而当其值超过3.55 后进程就会被kill

  • 总之,使用DDMS 的Heap 视图工具可以很方便的确认我们的程序是否存在内存泄漏的可能性

Leakcanary

Square出品,内存泄露监测神器,GitHub地址

Eclipse Memory Analyzer(MAT)

这里写图片描述

内存分析工具,这个工具分为Eclipse插件版和独立版两种,如果你是使用Eclipse开发的,那么可以使用插件版MAT,非常方便。如果你是使用Android Studio开发的,那么就只能使用独立版的MAT了

HPROF文件

这里写图片描述

HPROF文件是MAT能识别的文件,HPROF文件存储的是特定时间点,java进程的内存快照

点击Dump HPROF file按钮,生成HPROF文件,这个文件记录着我们应用程序内部的所有数据。但是目前MAT还是无法打开这个文件的,我们还需要将这个HPROF文件从Dalvik格式转换成J2SE格式,使用hprof-conv命令就可以完成转换工作

hprof-conv dump.hprof converted-dump.hprof 

Histogram

Histogram:列出内存中每个对象的名字、数量以及大小
Shallow Heap:当前对象自己所占内存的大小,不包含引用关系的

析大内存的对象,分析对象的数量

这里写图片描述

Dominator Tree

Dominator Tree:列出最大的对象以及其依赖存活的Object,并且我们可以分析对象之间的引用结构

Retained Heap

表示这个对象以及它所持有的其它引用(包括直接和间接)所占的总内存

在每一行的最左边都有一个文件型的图标,这些图标有的左下角带有一个红色的点,有的则没有。带有红点的对象就表示是可以被GC Roots访问到的,可以被GC Root访问到的对象都是无法被回收的。带红点的对象最右边都有写一个System Class,说明这是一个由系统管理的对象,并不是由我们自己创建并导致内存泄漏的对象

搜索大内存对象通向GC Roots的路径,因为内存占用越高的对象越值得怀疑

GC Roots reference chain(引用链)的起点,是一个在current thread(当前线程)的call stack(调用栈)上的对象(例如方法参数和局部变量),或者是线程自身或者是system class loader(系统类加载器)加载的类以及native code(本地代码)保留的活动对象。所以GC Roots是分析对象为何还存活于内存中的利器。

这里写图片描述

这里写图片描述

dumpsys meminfo命令

adb shell dumpsys meminfo <package_name|pid> [-d]

命令后面带-d标志会打印出更多关于内存使用的信息

adb shell dumpsys meminfo com.google.android.apps.maps -d
C:\Users\AllenIverson>adb shell dumpsys meminfo com.qq.googleplay -dApplications Memory Usage (kB):Uptime: 588545781 Realtime: 1460567078** MEMINFO in pid 19204 [com.qq.googleplay] **                   Pss  Private  Private  Swapped     Heap     Heap     Heap                 Total    Dirty    Clean    Dirty     Size    Alloc     Free                ------   ------   ------   ------   ------   ------   ------  Native Heap        0        0        0        0    20480     9524    10955  Dalvik Heap    23402    22936        0        0    40714    38963     1751 Dalvik Other      729      728        0        0        Stack      392      392        0        0    Other dev        5        0        4        0     .so mmap     1586      232      468        0    .apk mmap      281        0       52        0    .ttf mmap      262        0      248        0    .dex mmap     5500        0     5356        0    .oat mmap     2606        0      916        0    .art mmap     2350      924      800        0   Other mmap     1342        4      884        0      Unknown     7798     7748        0        0        TOTAL    46253    32964     8728        0    61194    48487    12706 Objects               Views:      261         ViewRootImpl:        1         AppContexts:        3           Activities:        1              Assets:        4        AssetManagers:        4       Local Binders:        7        Proxy Binders:       16       Parcel memory:        5         Parcel count:       23    Death Recipients:        0      OpenSSL Sockets:        0 Dalvik         isLargeHeap:    false SQL         MEMORY_USED:        0  PAGECACHE_OVERFLOW:        0          MALLOC_SIZE:        0

一般我们只需要关心Pss Total和Private Dirty两列数据,在某些情况下,Private Clean和Heap Alloc两列数据可能会提供你感兴趣的数据

adb shell dumpsys batterystats 电量状态

Lint工具

这里写图片描述

使用Lint进行资源及冗余UI布局等优化,Lint 有自动修复、提示建议和直接跳转到问题处的功能

集成到androidstudio,点击工具栏的Analysis -> Inspect Code
内存抖动:短时间内有大量频繁的对象创建与释放操作

Lint是Android提供的一个静态扫描应用源码并找出其中的潜在问题的一个强大的工具

运行Lint:点击工具栏的Analysis -> Inspect Code

ProGuard

混淆代码,压缩和优化代码,apk瘦身

GC打印

当发生GC垃圾回收的时候,会在logcat打印日志

I/art : Explicit concurrent mark sweep GC freed 104710(7MB) AllocSpace objects, 21(416KB) LOS objects, 33% free, 25MB/38MB, paused 1.230ms total 67.216ms

Investigating Your RAM Usage

http://android.xsoftlab.net/tools/debugging/debugging-memory.html

1 0