使用工具:
可使用android studio工具进行监测:
还可以使用LeakCanary和MAT进行分析;
常见的泄露:
Context:在项目中遇到context泄露的问题,当activity的context被static的类给强引用了导致activity不能被回收,有一个办法就是设置软引用,但这也不可,因为很可能会报空指针错误;所以可以使用ApplicationContext,因为ApplicationContext的生命周期也是伴随进程的不需要被回收。但是不能都使用applicationcontext,因为有些场景是不能用的,例如需要涉及UI的。因此可以尽量使用applicationcontext,在涉及UI的部分就使用Activity Context并且注意内存泄露。
下面引用一下鸿洋大神博客的一张图:
使用Handler时要注意内存泄露的可能:因为handler被创建实例后会被发送到消息队列的message拥有一个强引用,当message一直存在于消息队列时,handler就不会被回收;如果它是一个匿名类或者是非静态内部类时,那么就会持有外部类的引用导致外部类不能被回收;
解决方法:可以设置Handler为静态内部类,当需要外部类时,将外部类设置为弱引用;
如下引用别人代码:
public class SampleActivity extends Activity {
/**
* Instances of static inner classes do not hold an implicit
* reference to their outer class.
*/
private static class MyHandler extends Handler {
private final WeakReference<SampleActivity> mActivity;
public MyHandler(SampleActivity activity) {
mActivity = new WeakReference<SampleActivity>(activity);
}
@Override
public void handleMessage(Message msg) {
SampleActivity activity = mActivity.get();
if (activity != null) {
// ...
}
}
}
private final MyHandler mHandler = new MyHandler(this);
/**
* Instances of anonymous classes do not hold an implicit
* reference to their outer class when they are "static".
*/
private static final Runnable sRunnable = new Runnable() {
@Override
public void run() { /* ... */ }
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Post a message and delay its execution for 10 minutes.
mHandler.postDelayed(sRunnable, 1000 * 60 * 10);
// Go back to the previous Activity.
finish();
}
}
使用HandlerThead时也要注意:因为HandlerThread实现的run方法是一个无限循环,它不会自己结束,线程的生命周期超过了activity生命周期,当横竖屏切换,HandlerThread线程的数量会随着activity重建次数的增加而增加。
应该在onDestroy时将线程停止掉:mThread.getLooper().quit();
另外,对于不是HandlerThread的线程,也应该确保activity消耗后,线程已经终止,可以这样做:在onDestroy时调用mThread.join();
项目中的遇到的知识点和问题总结(备注):
在我的项目中就出现了使用context被static对象引用导致不能回收
静态内部类的对象:首先多次new是在堆中创建了不同的对象,和普通类的对象一样。我在使用的时候,主要怕多个静态内部类的对象在程序运行过程中像静态成员变量一样一直占据内存空间导致OOM,经过验证,静态内部类的对象虽然每次new都生成一个对象,但是会被及时的回收,不会因为一直占据内存空间导致OOM。
$后面跟数字是匿名类编译出来的
$后面跟文字是内部类编译出来的