一、Android Monitor
1 生成.hprof文件
Android Monitor是AndroidStudio自带工具,可以查看内存、网络、CPU使用情况,选定程序可以分析应用的资源使用,内存看CPU
在Memory窗口显示时,先点击几次GC(垃圾回收),内存稳定后,点击生成内存.hprof文件
2 分析
在打开.hprof文件的视图窗口中,选择appheap、Arrange by Package,找到自己的包,以及对应的类
下方视图:
Total Count 类对应对象的个数
Heap Count 堆内存中个数
Size of 物理大小
Shallow Size 对象本身占多大内存
Retained Size 释放后节省多少内存
右侧视图:
Instance:
Depth:深度
Shallow Size 对象实例大小
Dominating Size 对象管辖的内存大小
**注意:**工具本身不能解决内存泄露问题,而是帮助我们找到泄露的问题所在
3 查找步骤:
- 查找引用了该对象的外部对象有那些
- 然后一个一个去观察,查找可能内存泄露的地方,(看生命周期是否一致/读代码,可以通过快照对比)如果生命周期一致,则无泄露
二、MAT
三、设置监听导致的内存泄漏
1 Demo
MyView
public class MyView extends View {
public MyView(Context context) {
super(context);
init();
}
public MyView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
ListenerCollector collector = new ListenerCollector();
collector.setListener(this,myListener);
}
public interface MyListener {
void mylistenerCallback();
}
private MyListener myListener = new MyListener() {
@Override
public void mylistenerCallback() {
System.out.print("被调用");
}
};
}
ListenerCollector
public class ListenerCollector {
static private WeakHashMap<View, MyView.MyListener> slistener = new WeakHashMap<>();
public void setListener(View view, MyView.MyListener listener) {
slistener.put(view, listener);
}
public static void clearListeners() {
//移除所有监听
slistener.clear();
}
}
ListenerActivity
public class ListenerActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
MyView myView = new MyView(this);
setContentView(myView);
}
/* @Override
protected void onStop() {
super.onStop();
ListenerCollector.clearListeners();
}*/
}
2 出现泄漏
运行进入这个Activity的页面,横屏后,分析内存,发现Activity泄漏
3 查找原因
-
Mat打开转换后的.hprof文件->Histogram视图
-
搜索要查找的类如MainActivity(relgex),搜索(Regex -enter键),右键搜索结果,List objects(查看被谁引用和引用了谁),选择with incoming references查看被引用情况
-
分析技巧:排除容易被回收的(软引用、虚引用、弱引用),右键搜索结果,
Path To GC Roots - exclude all phantom/weak/soft etc. references
最终我们找到了不能被回收导致Activity泄漏的地方 -
解决方法:Activity的onStop清除监听 ListenerCollector.clearListeners();
-
Demo:ListenerActivity
4 MAT两个.hprof文件进行对比
选中一个.hprof文件,点击Navigation History - 选中histogram-Add to Compare Basket ,再选中另一.hprof文件重复操作;然后右上角compare the results
找到对应的Activity,看看是否泄漏