Android 内存泄漏的几种可能:
一般内存泄漏的原因是:由忘记释放分配的内存导致的(cursor、stream等)
逻辑内存泄漏的原因是:当应用不再需要这个对象,仍未释放该对象的所有引用。
(1)static Activity:
在类中定义了静态Activity变量,把当前运行的Activity实例赋值于这个静态变量,如果这个静态变量在Activity生命周期结束后
没有清空,就会导致内存泄漏。因为static变量时贯穿这个应用的生命周期的,导致这个Activity会一直存在应用进程中。
static Activity activity;
void setStaticActivity() {
activity = this;
}
View saButton = findViewById(R.id.sa_button);
saButton.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
setStaticActivity();
nextActivity();
}
});
解决办法:
使用弱引用代替强引用
private static WeakReference<MainActivity> activityReference;
void setStaticActivity() {
activityReference = new WeakReference<MainActivity>(this);
}
(2)static View:
如果一个View的初始化耗费大量资源,而且一个Activity生命周期保持不变,那么可以把它变成static,加载到视图树上。当
Activity销毁事,应当释放资源。(这个static view应当置null)
static view;
void setStaticView() {
view = findViewById(R.id.sv_button);
}
View svButton = findViewById(R.id.sv_button);
svButton.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
setStaticView();
nextActivity();
}
});
解决办法:使用弱引用或者置空的方式来清除引用
private static View view;
@Override
public void onDestroy() {
super.onDestroy();
if (view != null) {
unsetStaticView();
}
}
void unsetStaticView() {
view = null;
}
(3)Inner class
假设Activity中有个内部类,这样做可以提高可读性和封装性,但是假如我们创建一个内部类,而且持有一个静态变量的引用,那么
内存泄漏就离你不远了(需要销毁的时候置空)内部类的优势之一就是可以访问外部类,但不幸的是,导致内存泄漏的原因就是nei
部类持有外部类实例的强引用。
private static Object inner;
void createInnerClass() {
class InnerClass {
}
inner = new InnerClass();
}
View icButton = findViewById(R.id.ic_button);
icButton.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
createInnerClass();
nextActivity();
}
});
解决办法:
避免静态变量
private Object inner;
void createInnerClass() {
class InnerClass {
}
inner = new InnerClass();
}
(4)匿名内部类,当再activity中定义了匿名的AsyncTask。当异步任务在后台执行耗时任务期间,Activity被销毁,这个被
AsyncTask持有的Activity实例就不会内垃圾回收器回收,知道异步任务结束。
void startAsyncTask() {
new AsyncTask<Void, Void, Void>() {
@Override protected Void doInBackground(Void... params) {
while(true);
}
}.execute();
}
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
View aicButton = findViewById(R.id.at_button);
aicButton.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
startAsyncTask();
nextActivity();
}
});
解决办法:
不能通过移除静态成员变量解决,因为线程是与生命周期相关的,为了避免泄漏,必须舍弃匿名的写法,把子类生命为静态内部类。
静态内部类不持有外部类的引用,打破了链式引用。
private static class NimbleTask extends AsyncTask<Void, Void, Void> {
@Override protected Void doInBackground(Void... params) {
while(true);
}
}
void startAsyncTask() {
new NimbleTask().execute();
}
(5)handler
定义匿名的Runnable,用匿名类Handler执行,Runnable内部类会持有外部类的隐式引用,被传递到Handler的消息对象MessageQueue中,在Message
消息还没有被吃力之前,Activity实例不会被销毁,导致内存泄漏。
void createHandler() {
new Handler() {
@Override public void handleMessage(Message message) {
super.handleMessage(message);
}
}.postDelayed(new Runnable() {
@Override public void run() {
while(true);
}
}, Long.MAX_VALUE >> 1);
}
View hButton = findViewById(R.id.h_button);
hButton.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
createHandler();
nextActivity();
}
});
解决办法:
private static class NimbleHandler extends Handler {
@Override public void handleMessage(Message message) {
super.handleMessage(message);
}
}
private static class NimbleRunnable implements Runnable {
@Override public void run() {
while(true);
}
}
void createHandler() {
new NimbleHandler().postDelayed(new NimbleRunnable(), Long.MAX_VALUE >> 1);
}
(6)Thread和TimerTask的不合理使用导致内存泄漏。只要是匿名类的实例,不管是不是在工作线程,都会持有Activity的引用,导致内存泄漏。
void spawnThread() {
new Thread() {
@Override public void run() {
while(true);
}
}.start();
}
View tButton = findViewById(R.id.t_button);
tButton.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
spawnThread();
nextActivity();
}
});
void scheduleTimer() {
new Timer().schedule(new TimerTask() {
@Override
public void run() {
while(true);
}
}, Long.MAX_VALUE >> 1);
}
View ttButton = findViewById(R.id.tt_button);
ttButton.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
scheduleTimer();
nextActivity();
}
});
解决办法:
private static class NimbleTimerTask extends TimerTask {
@Override public void run() {
while(true);
}
}
void scheduleTimer() {
new Timer().schedule(new NimbleTimerTask(), Long.MAX_VALUE >> 1);
}
(7)Context.getSystemService(int name)可以获取系统服务,
这些服务工作在各自的进程中,帮助应用处理后台任务,硬件交互。使用这些服务的时候,可以注册监听器,这会导致服务持有了
Context的引用,如果Activity销毁的时候没有注销这些监听器,会导致内存泄漏。
void registerListener() {
SensorManager sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
Sensor sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ALL);
sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_FASTEST);
}
View smButton = findViewById(R.id.sm_button);
smButton.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
registerListener();
nextActivity();
}
});
解决办法:在Activity结束时注销监听器
private SensorManager sensorManager;
private Sensor sensor;
@Override
public void onDestroy() {
super.onDestroy();
if (sensor != null) {
unregisterListener();
}
}
void unregisterListener() {
sensorManager.unregisterListener(this, sensor);
}