内存泄漏就是我们对某一内存空间的使用,使用完成后没有释放。
1. 资源释放问题
长期保持某些资源,如 Context、Cursor、IO 流的引用,资源得不到释放 造成内存泄露。
2. 对象内存过大问题
保存了多个耗用内存过大的对象,如 Bitmap、XML 文件等,造成内存超出限制。
3. static关键字的使用问题
static 是 Java 中的一个关键字,当用它来修饰成员变量时,那么该变量就属于该类,而不是该类的实例。所以用 static 修饰的变量,它的生命周期是很长的,如果用它来引用一些资源耗费过多的实例(Context 的情况最多),这时就要谨慎对待了。如下
public class ClassName { private static Context mContext; }
以上的代码是很危险的,如果将 Activity 赋值到 mContext 的话。那么即使该 Activity 已经 onDestroy,但是由于仍有对象保存它的引用,因此该 Activity 依然不会被释放。
针对 static 的解决方案
1) 应该尽量避免 static 成员变量引用资源耗费过多的实例,比如 Context。
2) Context尽量使用ApplicationContext,因为Application的Context的生命周期比较长,引用它不会出现内存泄露的问题。
3) 使用 WeakReference 代替强引用. 比如可以使用 WeakReference<Context> mContextRef;
4.集合类泄漏
集合类如果只有添加元素的方法,而没有相应的删除机制导致内存被占用.
5.单例造成的内存泄漏
由于单例的静态特性使得其生命周期和应用的生命周期一样长,所以如果使用不当就会造成内存泄漏.比如需要传入一个 context, 如果传入的是 application 的 context, 因为 application 的生命周期是整个应用的生命周期,所以不会有任何问题.如果传入的是 Activity 的 context, 当 Context 对应的 activity 退出时,由于该 Context 的引用被单例对象所持有,其生命周期等于整个应用的生命周期,所以当前 activity 退出时它的内存不会被回收,这就造成了内存泄漏.可以使用 context.getApplicationContext()
6.非静态内部类创建静态实例造成内存泄漏
在 activity 内部创建一个非静态内部类的单例,每次启动 Activity 时都会使用该单例的数据,这样虽然 避免了资源的重复创建,但是会造成内存泄漏,因为非静态内部类默认会持有外部类的引用.可以将内部类设 置为静态内部类或者抽取出来封装成一个单例
7.匿名内部类如果被异步线程持有,此时如果没有任何措施则会造成内存泄漏
8.Handler 造成内存泄漏
我们知道 Handler、Message 和 MessageQueue 都是相互关联在一起的,万一 Handler 发送的 Message 尚未被处理,则该 Message 及发送它的 Handler 对象将被线程 MessageQueue 一直持有。因 Handler 为非静态内部类,它会持有外部类的引用,因此可以将 Handler 声明为静态的
9.线程造成的内存泄漏
例如:AsyncTask和Runnable
AsyncTask和Runnable都使用了匿名内部类,那么它们将持有其所在Activity的隐式引用。如果任务在Activity销毁之前还未完成,那么将导致Activity的内存资源无法被回收,从而造成内存泄漏。
解决方法:将AsyncTask和Runnable类独立出来或者使用静态内部类,这样便可以避免内存泄漏。
10.WebView造成的内存泄漏
当我们不要使用WebView对象时,应该调用它的destory()函数来销毁它,并释放其占用的内存,否则其长期占用的内存也不能被回收,从而造成内存泄露。
解决方法:
为WebView另外开启一个进程,通过AIDL与主线程进行通信,WebView所在的进程可以根据业务的需要选择合适的时机进行销毁,从而达到内存的完整释放。