您的位置:首页 > 移动开发 > Android开发

android内存泄漏与解决方案

2016-11-16 13:58 417 查看
android内存泄漏与解决方案

应用场景

android系统为每个应用分配的java object heap都是固定的,如果我们不及时释放废弃资源所占用的内存空间,那么就会使我们的程序运行起来非常卡顿,当超过系统为我们分配的内存空间时,系统就会抛出OOM

内存泄漏原因

我们开发者不需要它存在的一些资源,但是因为种种原因,这部分资源不能够被GC回收掉,这便会造成内存泄漏,通俗点讲是“该死不死”,下面我将对这“种种原因”来做一下分析

Activity内存泄漏

原因

当activity被废弃销毁时,因为activity中的部分对象还持有对activity的引用,这使得GC没办法对废弃的activity的一个回收。

解决方案

1.不要让生命周期长的对象引用activity context,既保证引用activity的对象要与activity本身的生命周期一样长。

2.比如,如果引用context的对象声明周期长于activity的那么最好选用application context代替。

3.应注意handler的使用,一般大家使用的时候采用非静态匿名内部类的使用方式,如果handler长于activity的生命周期时,非静态内部类持有外部类的引用,这时便会造成内存泄漏,我们应该将其写成静态内部类,并弱引用activity对象。

代码示下

public class MainActivity extends Activity {

private TextView tvHelloWorld;
private Button btnSetText;
private Handler mHandler = new InternalHandler(this);

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnSetText = (Button) findViewById(R.id.btn_set_text);
tvHelloWorld = (TextView) findViewById(R.id.tv_hello_world);
btnSetText.setOnClickListener(new OnClickListener() {

@Override
public void onClick(View v) {
mHandler.post(new Runnable() {

@Override
public void run() {
tvHelloWorld.setText("Runnable");
}

});
}

});
}

private static class InternalHandler extends Handler {
private WeakReference<Activity> weakRefActivity;

/**
* A constructor that gets a weak reference to the enclosing class. We
* do this to avoid memory leaks during Java Garbage Collection.
*/
public InternalHandler(Activity activity) {
weakRefActivity = new WeakReference<Activity>(activity);
}

@Override
public void handleMessage(Message msg) {
Activity activity = weakRefActivity.get();
if (activity != null) {

}
}
}
}
同样,AsyncTask内部也是Handler机制,同样也存在相同问题。
4.同样也要注意,非静态内部类的静态实例化对象,然后此静态实例化对象被外部比activity生命周期长的对象所持有同样也会造成内存泄漏问题,这种造成内存泄漏的机制与本文第三条基本相同。我们在不用时应注意要将静态变量置为null,这样便于GC的回收。

5.注意activity被静态集合引用导致activity不能释放。

6.在activity中使用Thread、Timer Tasks、广播接收者、Sensor Manager等要在onDestroy方法中释放掉。

资源文件泄漏

原因

当使用了BraodcastReceiver、ContentObserver、Cursor、Bitmap、File等资源时,当不需要使用时,需要及时释放掉,若没有释放,则会引起内存泄漏。

解决方案

1.BraodcastReceiver的注册与反注册

//注册
registerReceiver(mFinishReceiver, filter);
//反注册
unregisterReceiver(mFinishReceiver);
2.ContentObserver的注册与反注册
//注册
getContentResolver().registerContentObserver(uri, true, observer);
//反注册
getContentResolver().unregisterContentObserver(observer);

3.Cursor
Cursor cursor = null;
try{
cursor = mContext.getContentResolver().query(uri,null,null,null,null);
if(cursor != null){
cursor.moveToFirst();
//do something
}
}catch(Exception e){
e.printStatckTrace();
}finally{
if(cursor != null){
cursor.close();
}
}
有一种情况下,我们不能直接将Cursor关闭掉,这就是在CursorAdapter中应用的情况,但是注意,CursorAdapter在Acivity结束时并没有自动的将Cursor关闭掉,因此,你需要在onDestroy函数中,手动关闭。
@Override
protected void onDestroy() {
if (mAdapter != null && mAdapter.getCurosr() != null) {
mAdapter.getCursor().close();
}
super.onDestroy();
}4.Bitmap
Bitmap bit = BitmapFactory.decodeFile(path);
if(bit != null && !bit.isRecycled()) {
bit.recycle();
} 5.File
File file = new File("/home/admin/a.txt");
FileOutputStream  out = null;
try {
out = new FileOutputStream(file);
file.delete();
while(true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(out!=null) {
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}

}

单例造成的内存泄漏

原因

单例模式非常受开发者的喜爱,不过使用的不恰当的话也会造成内存泄漏,由于单例的静态特性使得单例的生命周期和应用的生命周期一样长,这就说明了如果一个对象已经不需要使用了,而单例对象还持有该对象的引用,那么这个对象将不能被正常回收,这就导致了内存泄漏。如下这个典例:

public class AppManager {
private static AppManager instance;
private Context context;
private AppManager(Context context) {
this.context = context;
}
public static AppManager getInstance(Context context) {
if (instance != null) {
instance = new AppManager(context);
}
return instance;
}
}

总结

归根结底,内存泄漏问题就是不用的资源仍然占据着内存资源,因为我们不合理的代码结构导致这些被废弃的仍然被持有,GC无法进行回收。也就是我们上面分析的常见的场景,但是我们也要注意static的使用毕竟它是常驻内存的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息