TextVersion_02_内存泄漏

来源:互联网 发布:学生管理系统设计c语言 编辑:程序博客网 时间:2024/05/16 03:42


内存泄漏


内存在使用完之后没有被释放,那么就是内存泄漏

一次两次内存泄漏不会造成什么致命的错误

但是内存泄漏多了之后,小则非常影响性能,大则直接导致内存溢出


 

什么情况会导致内存泄漏

 

1.资源释放问题

长期保持某些资源,比如Context,Cursor,IO流的引用,资源得不到释放造成内存泄漏

 

2.对象内存过大问题

保存了多个耗用内存过大的对象(如 BitmapXML文件),造成内存超出限制。

 

 

3.static 关键字的使用问题

 

staticJava中的一个关键字,当用他来修饰成员变量时,那么该变量就属于该类,而不是该类的实例

所以用static修饰的变量,生命周期是很长的

如果用他来引用一些资源耗费过多的实例(Context的情况最多),  就要谨慎对待了

 

打个比方

 

public class ClassName{

private static Context mContext;

}

 

这样的代码是非常危险的

如果把Activity赋值到mContext的话,

就算这个Activity已经onDestroy,

但是由于仍然有对象保存他的引用,那么这个Activity还是不会被释放

 

 

再举个Android官方文档中的栗子

 

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(...)

 

然后是判断,如果为sBackgroundnull

那么sBackground=getDrawable(R.drawable.large_bitmap);

注意了:

这里虽然没有显式的保存Context的引用,

但是,DrawableView连接了之后,Drawable就将View设置为一个回调

由于View中是包含了Context的引用的,

所以实际上还是保存了Context的引用

引用链: Drawable--TextView--Context

所以,Context还是没有被释放,发生了内存泄漏

 

 

针对static的解决方案

 

1.尽量避免static成员变量引用资源耗费过多的实例,比如Context

2.Context尽量使用ApplicationContext,因为ApplicationContext的生命周期很长,

引用它不会出现内存泄漏的问题

3.使用WeakReference代替强引用,比如可以使用WeakReference<Context>   mContextReference;

 

 

4.线程导致内存泄漏

线程产生泄漏的主要原因

 

线程产生内存泄露的主要原因在于线程生命周期的不可控

 

 

 

看看一段简单的代码

 

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一个问题:

如果MyThreadrun方法是一个很费时的操作,

我们开启这个线程,然后中途我们把设备的横屏变成了竖屏,

一般屏幕转换的时候会重新创建Activity,

我们普遍会认为Activity会被销毁再重建,但是其实不是这样的,

 

由于我们的线程是Activity的内部类,所以MyThread保存了Activity的一个引用,

MyThreadrun方法没有结束的时候,MyThread是不会被销毁的,所以他引用的这个Activity也不会被销毁

所以就内存泄漏了

 

 

 

 

 

 

有些人喜欢用Android提供的AsyncTask,其实AsyncTask的问题更严重

 

Thread只有在run方法没结束的时候才出现这种内存泄漏问题

但是AsyncTask内部实现机制运用了ThreadPoolExcutor,

这个类产生的Thread对象的生命周期是不确定的,应用程序都无法控制

所以如果用了AsyncTask作为Activity的内部类,

更容易出现内存泄漏

 

解决:

 

1. 把线程的内部类,改成静态内部类(因为非静态内部类拥有外部类对象的强引用,静态类则不拥有)

2. 在线程内部采用弱引用保存Context引用

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

1 0
原创粉丝点击