1、内存分析
点击MEMORY,可以看到正在运行进程的各种内存使用情况
Tips:点击右上角的垃圾桶图标会触发强制gc
1.1、查看Java堆内存和Java实例
执行以下代码:
说明:list为MainActivity的全局变量,所以list的只有在MainAcitivity对象被销毁时才会销毁。list中持有3个People引用,所以三个People实例暂时不会被gc。
点击任意一个时间点,可以查看该事件对应的堆内存的使用情况了。(部分手机用这个方法好像不太管用,所以换成了下面那种方法查看堆内存)
点击右上角“dump java heap”按钮,也可以看到当前java堆内存中的使用情况。(这个方法比较好使)
然后就能看到app堆内存中的所有类和实例信息了
搜索了一下“People”,就能找到堆内存中有3个实例
参数说明:
Shallow Size
对象自身占用的内存大小,不包括它引用的对象。
针对非数组类型的对象,它的大小就是对象与它所有的成员变量大小的总和。当然这里面还会包括一些java语言特性的数据存储单元。
针对数组类型的对象,它的大小是数组元素对象的大小总和。
Retained Size
Retained Size=当前对象大小+当前对象可直接或间接引用到的对象的大小总和。(间接引用的含义:A->B->C, C就是间接引用)
换句话说,Retained Size就是当前对象被GC后,从Heap上总共能释放掉的内存。
不过,释放的时候还要排除被GC Roots直接或间接引用的对象。他们暂时不会被被当做Garbage。
1.2、内存泄漏问题
先构造一个内存泄漏的例子
创建一个LeakActivity,每次启动LeakActivity都会创建一个Hanlder类延时发送一个空消息。
说明:mHandler为匿名内部类的实例,会持有外部类LeakActivity的引用。每次关闭LeakActivity的时候,如果mHanlder中的任务还没有执行完就不会被销毁,同时因为mHanlder持有LeakActivity,所以导致本应该销毁的LeakActivity对象却没有被销毁,从而造成LeakActivity泄漏。
连续5次打开LeakActivity后关闭,会发现每次打开LeakActivity内存都会上涨一点点,发现内存在增加。
点击dump Java Heap,搜索“LeakActivity”,就可以看到泄漏的5个LeakActivity实例了 (Android Profiler工具已经显示Leak警告)
点击InstanceList中有实例,再点击References,就能看到该对象的引用链了
可以看到LeakActivity中的this0引用的值是mHandler实例。
这个时候就找到了内存泄漏的原因了,可以通过用将Hanlder变成静态内部类的方式来解决内存泄漏的问题。(因为静态内部类不会持有外部类的引用)
2、CPU分析
可以查看应用程序的实时CPU使用率(占总可用CPU时间的百分比)、当前应用程序的线程总数、其他APP的CPU使用率。该选项还可以查看函数的调用情况,执行时间等等
先了解以下几点知识:(以下部分内容摘选自Android Profile CPU使用 - 简书)
Wall clock time
表示实际经过时间。
Thread time
计时信息表示实际的消耗时间减去不消耗CPU资源的那段时间的任何部分。对于任何给定的方法,它的线程时间总是小于或等于它的时钟时间。使用线程时间让您更好地了解给定方法所消耗的线程实际CPU使用量。
Call Chart
Call Chart选项卡提供一个方法跟踪的图形表示,其中一个方法调用(或调用者)的周期和时间在水平轴上表示,而它的callees则显示在垂直轴上。对系统api的方法调用以橙色显示,调用您的应用程序自己的方法以绿色显示,方法调用第三方api(包括java语言api)以蓝色显示。下面的图显示了一个示例调用图,并说明了给定方法的自时间、子时间和总时间的概念。
转存失败重新上传取消
Flame Chart
火焰图选项卡提供了一个反向调用图表,聚合了相同的调用堆栈。也就是说,收集相同的调用序列的相同方法被收集并表示为火焰图中的一个较长的栏(而不是将它们显示为多个更短的条,如调用图所示)。这样就更容易看出哪些方法消耗的时间最多。然而,这也意味着横轴不再表示时间轴,相反,它表示每个方法执行的相对时间。
为了帮助说明这个概念,考虑下面图中的调用图表。注意,方法D对B(B1、B2和B3)进行多次调用,其中一些调用B对C(C1和C3)进行调用。
转存失败重新上传取消
因为B1、B2和B3共享相同的序列调用者(A→D→B)聚合,如下所示。同样,C1和C3聚合,因为它们共享相同的序列调用者(A→D→B→C)注意不包括C2,因为它有不同的调用者序列(A→D→C)。
转存失败重新上传取消
聚合方法调用用于创建flame 图,如下图所示。注意,对于任何给定的方法调用,在flame图中,消耗最多CPU时间的callees首先出现。
转存失败重新上传取消
Top Down
Top Down选项卡显示方法调用的列表,扩展方法节点显示其callees。下图显示了上面的图3中调用图的顶部向下图。图中的每个箭头都是从调用者到callee。
下图所示,在顶部的down选项卡中扩展方法A的节点将显示它的callees、方法B和D。在此之后,扩展方法D的节点将暴露它的callees、方法B和C,等等。与火焰图选项卡类似,顶部向下的树聚合跟踪信息,用于共享相同调用堆栈的相同方法。也就是说,火焰图标签提供了顶部下标签的图形表示。
Top Down选项卡提供以下信息,以帮助描述在每个方法调用上花费的CPU时间(在选定的时间段内,时间也代表线程总时间的百分比):
- Self:方法调用用于执行自己的代码而不是它的callees的时间量,如上面的图所示。
- Children:方法调用花费的时间用于执行其被调用者,而不是其自己的代码,如图中的方法D所示。
- Total:方法的Self和Children的时间的总和。这表示应用程序执行方法调用的总时间量,如图所示的方法D。
转存失败重新上传取消
Bottom Up
Bottom Up选项卡显示一个方法调用列表,扩展方法的节点显示其调用者。使用上图所示的例子中,下图提供了一个自下而上方法C .在自下而上的树中打开方法C的节点,显示每个独特的调用者,方法B和d .注意,虽然B两次调用C,B当扩大节点只出现一次自下而上方法C的树。再此之后,展开节点B显示其调用者方法A和D.
转存失败重新上传取消
Bottom Up选项卡对于那些消耗最多(或最少)CPU时间的方法的排序方法很有用。您可以检查每个节点,以确定哪些调用者在调用这些方法上花费最多的CPU时间。与上面的树相比,底部树中每个方法的定时信息都是在每棵树的顶部(顶部节点)的方法。在记录期间,CPU时间也被表示为线程总时间的百分比。下表有助于解释如何解释顶级节点及其调用方方法(子节点)的定时信息。
举一个例子:
查看Flame Chart
查看Top Down(从上到下查找耗时时间)
查看Bottom up(从下到上查找耗时时间)