内存在使用完之后没有被释放,那么就是内存泄漏
一次两次内存泄漏不会造成什么致命的错误
但是内存泄漏多了之后,小则非常影响性能,大则直接导致内存溢出
长期保持某些资源,比如Context,Cursor,IO流的引用,资源得不到释放造成内存泄漏
保存了多个耗用内存过大的对象(如 Bitmap、XML文件),造成内存超出限制。
static是Java中的一个关键字,当用他来修饰成员变量时,那么该变量就属于该类,而不是该类的实例
所以用static修饰的变量,生命周期是很长的
如果用他来引用一些资源耗费过多的实例(Context的情况最多), 就要谨慎对待了
public class ClassName{
private static Context mContext;
}
这样的代码是非常危险的
如果把Activity赋值到mContext的话,
就算这个Activity已经onDestroy了,
但是由于仍然有对象保存他的引用,那么这个Activity还是不会被释放
private static Drawable sBackground;
@Override
protected void onCreate(Bundle state) {
super.onCreate(state);
TextView label = new TextView(this); //getApplicationContext
label.setText("Leaks are bad");
if (sBackground == null) {
sBackground = getDrawable(R.drawable.large_bitmap);
}
label.setBackgroundDrawable(sBackground);
setContentView(label);
}
我们来看这段代码
先是有一个静态的Drawable sBackground
然后是onCreate方法
然后new了一个TextView,设置了一下Text(...)
然后是判断,如果为sBackground为null
那么sBackground=getDrawable(R.drawable.large_bitmap);
这里虽然没有显式的保存Context的引用,
但是,当Drawable与View连接了之后,Drawable就将View设置为一个回调
由于View中是包含了Context的引用的,
所以实际上还是保存了Context的引用
引用链: Drawable--TextView--Context
所以,Context还是没有被释放,发生了内存泄漏
1.尽量避免static成员变量引用资源耗费过多的实例,比如Context
2.Context尽量使用ApplicationContext,因为Application的Context的生命周期很长,
引用它不会出现内存泄漏的问题
3.使用WeakReference代替强引用,比如可以使用WeakReference
线程产生内存泄露的主要原因在于线程生命周期的不可控
public class MyActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
new MyThread().start();
}
private class MyThread extends Thread{
@Override
public void run() {
super.run();
//do somthing while(true)
}
}
}
这段代码很平常,我们思考d一个问题:
如果MyThread的run方法是一个很费时的操作,
我们开启这个线程,然后中途我们把设备的横屏变成了竖屏,
一般屏幕转换的时候会重新创建Activity,
我们普遍会认为Activity会被销毁再重建,但是其实不是这样的,
Thread只有在run方法没结束的时候才出现这种内存泄漏问题
但是AsyncTask内部实现机制运用了ThreadPoolExcutor,
这个类产生的Thread对象的生命周期是不确定的,应用程序都无法控制
所以如果用了AsyncTask作为Activity的内部类,
更容易出现内存泄漏
1. 把线程的内部类,改成静态内部类(因为非静态内部类拥有外部类对象的强引用,静态类则不拥有)
2. 在线程内部采用弱引用保存Context引用