检测内存泄漏的方法
1、Android device monitor --> memory
2、MAT(Memory Analyzer Tools):MAT下载地址
3、LeakCanary
强烈推荐:
Android Studio和MAT结合使用来分析内存问题
new Thread() :每次进入界面都会创建实例,并且不会被GC
非静态内存类的静态变量:只在第一次进入界面创建实例,并且不会被GC
Shallow Size
是对象本身占据的内存的大小,不包含其引用的对象。对于常规对象(非数组)的Shallow Size由其成员变量的数量和类型来定,而数组的ShallowSize由数组类型和数组长度来决定,它为数组元素大小的总和。
Retained Size
Retained Size=当前对象大小+当前对象可直接或间接引用到的对象的大小总和。(间接引用的含义:A->B->C,C就是间接引用) ,并且排除被GC Roots直接或者间接引用的对象
GC Root
JAVA虚拟机通过可达性(Reachability)来判断对象是否存活,
基本思想:以”GC Roots”的对象作为起始点向下搜索,搜索形成的路径称为引用链,
当一个对象到GC Roots没有任何引用链相连(即不可达的),则该对象被判定为可以被回收的对象,反之不能被回收。
GC Roots可以是以下任意对象
一个在current thread(当前线程)的call stack(调用栈)上的对象(例如方法参数和局部变量)
线程自身或者system class loader(系统类加载器)加载的类
native code(本地代码)保留的活动对象
Shallow Size、Retained Size、GC Root三者关系:
(1)只有强引用的对象(比如集合类型),在其对象中不断引用其他对象,这样才会导致memory leak.弱引用的对象会被GC回收从而不会导致memory leak.
(2)对于一个不引用其他自定义类对象的对象,它的Shallow Heap大小和Retained Heap大小相等,并且这个大小为这个对象的对象头(取决于平台是32位还是64位) 和所有成员变量的按照类型计算出的大小(如果是对象引用就是4个byte或者8个byte,也取决于平台是32位还是64位,这决定了你寻址用的地址的尺寸)的总和,并且做补位操作。
(3)对于一个引用其他自定义类对象的对象,它的Shallow Heap大小和Retained Heap大小不相等,Retained Heap尺寸为该对象自己的Shallow Heap大小加上它所有直接或者间接引用到的对象的大小的总和(不包括被GC Root直接间接引用的对象)
参考:通过分析Heap Dump 来了解 Memory Leak ,Retained Heap,Shallow Heap
Java堆:Shallow Size和Retained Size
内存泄漏
对于 C++ 来说,内存泄漏就是new出来的对象没有 delete,俗称野指针; 而对于 java 来说,就是 new 出来的 Object 放在 Heap 上无法被GC回收。
java的内存分配
静态存储区:编译时就分配好,在程序整个运行期间都存在。它主要存放静态数据和常量;
栈区:当方法执行时,会在栈区内存中创建方法体内部的局部变量,方法结束后自动释放内存;
堆区:通常用来存放new出来的对象。由java垃圾回收期回收。
四种引用类型的介绍
强引用(StrongReference):JVM 宁可抛出 OOM ,也不会让 GC 回收具有强引用的对象;
软引用(SoftReference):只有在内存空间不足时,才会被回的对象;
弱引用(WeakReference):在 GC 时,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存;
虚引用(PhantomReference):任何时候都可以被GC回收,当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。程序可以通过判断引用队列中是否存在该对象的虚引用,来了解这个对象是否将要被回收。可以用来作为GC回收Object的标志。
参考:
Android性能优化第(二)篇—Memory Monitor检测内存泄露
Android性能优化第(三)篇—MAT比Menmery Monitor更强大
Android性能优化第(四)篇—Android渲染机制
Android性能专项测试
一、Android device monitor --> memory的使用:
坐标系:
y轴:内存
x轴:时间
灰色区域:空闲的内存(未分配的内存)
蓝色区域:分配的内存(当前正在使用中的内存总量)
按钮:
enabled:
启动与关闭Memory监测按钮:
initiate GC:
小汽车,代表GC按钮 ,可以手动GC,回收程序垃圾
Dump Java Heap:
向下的箭头,代表内存快照 ,点击可以生成一个文件(包名+日期+“.hprof”),可以记录某一个时间点内,程序内存的情况
Start/stop Allocation Tracking :
按钮先点击一次,然后会看到Memory Recorder开始转动,然后自己开始在APP上面做相应的操作。在合适的时间再点一次,结束记录。
记录这段时间内的内存情况,也可以可以生成一个文件(包名+日期+“.alloc”)。
help:
帮助
AndroidStudio Memory使用流程:
1,运行要监控的程序(APP)后,打开Android Monitor控制台窗口,可以看到Memory控制台。
2,点击Memory控制台上Enable按钮,Memory控制台开始显示正在运行时程序的Memory使用情况。
3,单击启动GC图标。虚拟机发起的第一个垃圾回收事件。因为通常情况下,虚拟机是不会执行GC操作的,我们手动地进行GC操作来检测程序的内存使用等 情况。
4,点击Dump Java Heap按钮,APP会Freeze住。大概几十秒后,就会进入读取hprof文件的界面了,
这个文件记录着我们应用程序内部的所有数据,可以通过MAT等工具查看分析。
5,点击Starg Allocation Tracking按钮。开始分配追踪,过一些时间后,点击Stop Allocation Tracking结束追踪的位置。
这样就截取了一段要分析的内存,等待几秒钟AndroidStudio会给我们打开一个Allocation视图,
这个视图数据主要分析各个线程中的方法所占用内存的大小,从而可以找到需要优化的地方。
分析:
选择查看方式:
Heap类型分为:
App Heap -- 当前App使用的Heap
Image Heap -- 磁盘上当前App的内存映射拷贝
Zygote Heap -- Zygote进程Heap(每个App进程都是从Zygote孵化出来的, 这部分基本是framework中的通用的类的Heap)
view类型分为:
Class List View -- 类列表方式
Package Tree View -- 根据包结构的树状显示
板块A:class name这一栏,这个应用中所有类的名字
版块B:instance这一栏,左边类的所有实例
板块C:reference tree这一栏,在选择B中的实例后,这个实例的引用树
版块D:analyzer tasks这一栏,可以检测内存泄漏的activity
A板块左上角列名解释
Class Name 类名,Heap中的所有Class
Total Count 内存中该类这个对象总共的数量,有的在栈中,有的在堆中
Heap Count 堆内存中这个类 对象的个数
Sizeof 每个该实例占用的内存大小
Shallow Size 所有该类的实例占用的内存大小
Retained Size 所有该类对象被释放掉,会释放多少内存
B板块右上角上角列名解释
Instance 该类的实例
Depth 深度, 从任一GC Root点到该实例的最短跳数
Dominating Size 该实例可支配的内存大小
二、Mat的使用:
准备工作:在Android studio中左侧capture找到要检测的文件,并转为标准格式。
1、用mat工具打开
2、选择直方图:
3、选择group by package:
4、找到要检测的类比如:mainactivity,右键依次选择List objects–>with incoming references
注意:Activity或View大于1个对象, 都有可能发生内存泄露.
5、选择一个,右键依次选择path to GC toots -->exclude all Phantom /Weak / Soft etc. references(即只选择强引用导致的内存泄漏)
可以看到thread对mainactivity的强引用导致了内存泄漏。