Activity泄露,简单来说就是已经没有用的Activity,却由于各种原因(比如,被静态类持有引用)导致其不能被彻底的销毁,所占有的内存不能被回收。而通常一个Activity内会包含比较多的View之内的控件,这些控件也不会被回收,从而导致比较严重的内存资源浪费,慢慢积累导致最后内存资源不足,发送泄露。
常见的Activity泄露原因:(以下几种泄漏场景,根因类似,都是由于activity对象被比其生命周期更长的对象所引用,导致activity兑现无法及时被GC回收)
1)Activity被单例所引用
Singleton.instance().addListener(activityA);
这种场景,单例Singleton对象持有了activityA的强引用,那么在Singleton被销毁之前,activityA对象是不会被GC回收的。
解决这种问题,就必须保证在activityA被销毁前,去除Singleton对其的引用
Singleton.instance().removeListener(activityA);
这个时序必须得保证。(出现过由于时序问题,add看上去实在remove之前,实际却是在remove之后,最终导致泄露)
2)静态Activity
即Actvity对象被一个静态对象所引用
public class MainActivity extends Activity {
private static MainActivity activity;
...
public void setActivity() {
this.activity = this;
}
...
解决办法:在onpause()方法中将activity置为null,去除静态引用
3)静态view
public class MainActivity extends Activity {
private static View view;
...
void setView() {
this.view = findViewById(R.id.view);
}
...
}
由于view持有一个context的引用,这个就是我们的activity,这也会导致activity不能被及时回收。
4)内部的Handler导致的Activity泄露
内部非静态类是不能脱离所属类而单独存在的,会持有其外部类的强引用。(静态内部类不依赖所属类)
5)内部线程类导致的Activity泄露(类似内部Handler)
6)Toast中传入activity实例,类似1,传入ApplicationContext即可解决泄露问题
可以重载对象的finalize()方法,这个方法是在垃圾回收器准备释放对象所占用的存储空间时被调用的,不能直接调用这个方法。一般如果执行到这个方法,就表明这个对象要被被回收了(finalize()方法被调用并不表示gc会立即回收该对象)。