Android 常见内存泄漏
内存泄漏(Menory Leak)
进程中某些对象已经没有使用价值,但是他们却还是直接或间接地被引用到GC Root导致无法回收。
内存溢出(OOM)
当内存泄漏过多时,再加上应用本身占有的内存,日积月累最终就会导致内存溢出。
专业说法: 当应用占用的heap资源超过了虚拟机分配的内存就会内存溢出,比如加载大图片。
内存泄漏的影响
应用卡顿
- 泄漏的内存影响GC的内存分配,过多的内存泄漏会影响应用的执行效率
应用异常(OOM)
- 过多的内存泄漏,最终导致虚拟机可分配的内存越来越少,更加容易出现OOM
1. 静态变量、单例引用Activity和View
一直持有着Activity、View的引用,导致Activity无法被释放。静态变量、单例的Context不要传入Activity。
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SingleTon.getInstance(this); //错误
SingleTon.getInstance(getApplication()()); //正确
}
}
2. 非静态内部类(包括匿名内部类)
在java中,非静态内部类会隐式持有外部类,如果内部类没有被释放,那么外部类也不会被释放。
所以内部类应该使用static,这样可以避免内部类隐式持有外部类。
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void show(String message) {
Toast.makeText(MainActivity.this, message, Toast.LENGTH_SHORT).show();
}
static class Inner {
private Reference<MainActivity> activityRef;
public Inner(MainActivity activity) {
this.activityRef = new WeakReference(activity);
}
public void method1() {
MainActivity activity = this.activityRef.get();
if (activity == null) {
return; //activity为null说明activity已经被回收了
}
//调用activity
activity.show("hello world!");
}
}
}
比如Handler等,应使用静态内部类。
(2). 匿名内部类
匿名内部类对外部类都持有一个隐式引用。
比如AsyncTask和Thread,如果在Activity销毁前,任务还未完成,那么将导致Activity的内存资源无法回收,造成内存泄漏。
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new Thread() {
@Override
public void run() {
SystemClock.sleep(100 * 10);
}
}.start();
}
}
应该使用静态内部类来解决
3. 不需要的监听未移除
注册的监听需要在不使用的时候注销
(1).自己的监听
public class ThirdActivity extends AppCompatActivity
implements NotifyController.UpdateCallback {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_third);
NotifyController.registerCallback(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
//结束时应移除监听
NotifyController.unregisterCallback(this);
}
}
(2).系统的监听-示例1
SensorManager sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
Sensor sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ALL);
sensorManager.registerListener(this, SensorManager.SENSOR_DELAY_FASTEST);
//不用的时候,需要取消监听
sensorManager.unregisterListener(this);
(3).系统的监听-示例2
getWindow().getDecorView().getViewTreeObserver().addOnWindowFocusChangeListener(new ViewTreeObserver.OnWindowFocusChangeListener() {
@Override
public void onWindowFocusChanged(boolean b) {
//监听VIew的加载,View加载出来的时候,计算他的宽高
}
});
//不用的时候,需要取消监听
getWindow().getDecorView().getViewTreeObserver().removeOnWindowFocusChangeListener(this);
4.资源未关闭
对于使用BroadcastReceiver、ContentObserver、File、Cursor、Stream、Bitmap等资源的使用,应该在Activity销毁时及时关闭或者注销,否则这些资源将不会回收,造成内存泄漏。
Bitmap的回收
5. 无限循环动画
如果动画时无限循环的,记得要在Activity结束时,将其停止。
其他
参考
Android性能优化-内存泄漏的8个Case
Android 内存泄漏分析
Android开发必备技能:关于你所不知道的内存管理
Android OOM案例分析
还没有评论,来说两句吧...