Android 内存泄露与解决方案

时间:2021-09-11 20:56:55

内存泄露

Java内存泄漏指的是进程中某些对象(垃圾对象)已经没有使用价值了,但是它们却可以直接或间接地引用到gc roots导致无法被GC回收。无用的对象占据着内存空间,使得实际可使用内存变小,形象地说法就是内存泄漏了。下面分析一些可能导致内存泄漏的情景。

  • 非静态内部类的静态实例容易造成内存泄漏
  • activity使用静态成员
  • handler 非静态
  • 注册某个对象后未反注册
  • 资源对象没关闭造成的内存泄露
  • 构造Adapter时,没有使用缓存的 convertView

以上分析只是常见的问题,本质上是
* 全局进程(process-global)的static变量。这个无视应用的状态,持有Activity的强引用的怪物
* 活在Activity生命周期之外的线程。没有清空对Activity的强引用
可以参考下面文章的讲解及解决方式。本文重点是关注handler这类非静态引起及使用WeakReference, SoftReference来处理。

[译]Android内存泄漏的八种可能(上)

[译]Android防止内存泄漏的八种方法(下)

引例

先看 下面代码

public class SampleActivity extends Activity {

private final Handler mLeakyHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// ...
}
};

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

// Post a message and delay its execution for 10 minutes.
mLeakyHandler.postDelayed(new Runnable() {
@Override
public void run() { /* ... */ }
}, 1000 * 60 * 10);

// Go back to the previous Activity.
finish();
}
}

Activity的销毁会到10分钟后的handler执行完毕。解决办法其实有比较多的方案,这里使用WeakReference

解决方案

public class SampleActivity extends Activity {

/**
* Instances of static inner classes do not hold an implicit
* reference to their outer class.
*/

private static class MyHandler extends Handler {
private final WeakReference<SampleActivity> mActivity;

public MyHandler(SampleActivity activity) {
mActivity = new WeakReference<SampleActivity>(activity);
}

@Override
public void handleMessage(Message msg) {
SampleActivity activity = mActivity.get();
if (activity != null) {
// ...
}
}
}

private final MyHandler mHandler = new MyHandler(this);

/**
* Instances of anonymous classes do not hold an implicit
* reference to their outer class when they are "static".
*/

private static final Runnable sRunnable = new Runnable() {
@Override
public void run() { /* ... */ }
};

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

// Post a message and delay its execution for 10 minutes.
mHandler.postDelayed(sRunnable, 1000 * 60 * 10);

// Go back to the previous Activity.
finish();
}
}

这样一来Activity不再是handler的强引用了,对于重度Activity类如此来解决还是比较好的。
Finally understanding how references work in Android and Java讲到了WeakReference, SoftReference,PhantomReference,Strong reference.一般SoftReference更适合做Cache,在系统内存不足时才会清理。

Strong reference: strong references are the ordinary references in Java. Anytime we create a new object, a strong reference is by default created.

WeakReference: a weak reference is a reference not strong enough to keep the object in memory. If we try to determine if the object is strongly referenced and it happened to be through WeakReferences, the object will be garbage-collected.

SoftReference: think of a SoftReference as a stronger WeakReference. Whereas a WeakReference will be collected immediately, a SoftReference will beg to the GC to stay in memory unless there is no other option. The Garbage Collector algorithms are really thrilling and something you can dive in for hours and hours without getting tired. But basically, they say “I will always reclaim the WeakReference. If the object is a SoftReference, I will decide what to do based on the ecosystem conditions”. This makes a SoftReference very useful for the implementation of a cache: as long as the memory is plenty, we do not have to worry of manually removing objects.

PhantomReference: Ah, PhantomReferences! I think I can count on the fingers of one hand how often I saw them used in a production environment. An Object that has only being referenced through a PhantomReference them can be collected whenever the Garbage Collector wants. No further explanations, no “call me back”. This makes it hard to characterise. Why would we like to use such a thing? Are the other ones not problematic enough? Why did I choose to be a programmer? PhantomReference can be used exactly to detect when an object has been removed from memory. Being fully transparent, I recall two occasions when I had to use a PhantomReference in my entire professional career. So do not get stressed if they are hard to understand now.

参考链接