android内存泄漏总结,Android内存泄漏总结

Android内存泄漏常见场景

监听器

场景:html

public class LeaksActivity extends Activity implements LocationListener {

private LocationManager locationManager;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_leaks);

locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);

locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,

TimeUnit.MINUTES.toMillis(5), 100, this);

}

}

解释:

在这个例子中,咱们让Android的 LocationManager通知咱们位置更新。咱们所须要作的就是获取系统服务自己和设置一个回调来接收更新。在这里,咱们在Activity中实现了位置监听接口,这意味着LocationManager将持有该Activity的引用。

若是该设备被旋转,新的Activity将被建立并取代已经注册位置更新接口的旧的Activity。因为系统服务存活时间确定比任何Activity都要长,LocationManager仍然持有之前的Activity的引用,这使GC不可能回收依赖于之前的Activity的资源,从而致使内存泄漏。

解决办法:

在Activity的onDestroy方法里,将LocationManager监听移除便可。java

locationManager.removeUpdates(this);

内部类

以前有文章提到关于内部类的讲解,详细请移步到:Java内部类的总结 和 Java内存泄漏总结

能够看出,内部类的不正当使用也是内存泄漏的一个重要场景之一。内部类能够以这样的方式来定义:即只有外部类能够实例化它们。不少人可能没有意识到的是这样的类会持有外部类的隐式引用。隐式引用很容易出错,尤为是当两个类具备不一样的生命周期。

例如android

public class AsyncActivity extends Activity {

TextView textView;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_async);

textView = (TextView) findViewById(R.id.textView);

new BackgroundTask().execute();

}

private class BackgroundTask extends AsyncTask {

@Override

protected String doInBackground(Void... params) {

// Do background work. Code omitted.

return "some string";

}

@Override

protected void onPostExecute(String result) {

textView.setText(result);

}

}

}

解释:

因为BackgroundTask持有一个AsyncActivity隐式引用并运行在另外一个没有取消策略的线程上,它将保留AsyncActivity在内存中的全部资源链接,直到后台线程终止运行。web

解决办法:

1. 使用静态内部类,来消除指向Activity的引用,可是这样就不能直接访问textView了,所以须要第二步;

2. 添加一个构造函数,把textView做为参数传递进来。最后,咱们须要引入AsyncTask文档中所述的取消策略。

3. 可是这样仍是不行,因为textView持有一个mContext的引用,为了解决这个问题,一种简单的方法是使用WeakReference。咱们持有的resultTextView引用是强引用,具备防止GC回收的能力。相反,WeakReference不保证其引用的实例存活。当一个实例最后一个强引用被删除,GC会把其资源回收,而无论这个实例是否有弱引用。

最后,版本以下:async

public class AsyncActivity extends Activity {

TextView textView;

AsyncTask task;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_async);

textView = (TextView) findViewById(R.id.textView);

task = new BackgroundTask(textView).execute();

}

@Override

protected void onDestroy() {

task.cancel(true);

super.onDestroy();

}

private static class BackgroundTask extends AsyncTask {

private final WeakReference textViewReference;

public BackgroundTask(TextView resultTextView) {

this.textViewReference = new WeakReference<>(resultTextView);

}

@Override

protected void onCancelled() {

// Cancel task. Code omitted.

}

@Override

protected String doInBackground(Void... params) {

// Do background work. Code omitted.

return "some string";

}

@Override

protected void onPostExecute(String result) {

TextView view = textViewReference.get();

if (view != null) {

view.setText(result);

}

}

}

}

提醒一下:在onPostExecute咱们要检查空值,判断实例是否被回收。ide

匿名类

匿名类和内部类有一样的缺点,即他们持有外部类的引用。如同内部类,一个匿名类在Activity生命周期以外执行或在其余线程执行工做时,可能会致使内存泄漏。svg

结论

后台任务独立于Activity的生命周期运行是一件麻烦事。再加上须要协调用户界面和各类后台任务之间的数据流,所以处理很差容易致使内存泄漏。

1 尽可能使用静态内部类。每一个非静态内部类将持有一个外部类的隐式引用,这可能会致使没必要要的问题。使用静态内部类代替非静态内部类,并经过弱引用存储一些必要的生命周期引用。

2 考虑后台服务等手段, Android提供了多种在非主线程工做的方法,如HandlerThread,IntentService和AsyncTask,它们每一个都有本身的优缺点。另外,Android提供了一些机制来传递信息给主线程以更新UI。譬如,广播接收器就能够很方便实现这一点。函数

多说两句

关于上面的结论2 为何将内部类改成静态内部类 解释一下内部类和静态内部类的区别 以及 静态内部类的做用

首先,静态内部类能够说是内部类+一些使用约束条件,从使用的范围上来讲:内部类>静态内部类

说一下区别:

1 非静态内部类不能声明静态方法和变量 静态内部类能够声明静态方法和变量

2 非静态内部类能够访问外部类的方法和变量(不管是静态的仍是非静态的),即便外部类的方法和变量是private的,由于在编译的时候,非静态内部类会有一个外部类的一个成员变量,所以即便是private,非静态内部类也是能够访问的;而静态内部类不能够访问外部类的非静态成员,只可以引用外部类的静态成员。(这就是为何将内部类改成静态内部类的缘由),因此,使用静态内部类的话,能够有效防止编码人员错误的引用了外部变量,致使内存泄漏的状况。this

参考

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值