一、造成内存泄露的原因分析
Android系统虚拟机的垃圾回收是通过虚拟机的GC机制来实现的,GC会选择一些存活的对象作为GC Root,通过对GC的可达性判断是否需要回收。
程序设计者在编写代码的时候,应该尽量将需要被GC回收的对象的引用断开,这些没有与GC Root直接或间接相连的对象可以被GC回收。
- 强引用,大部分对象持有的引用类型,不再使用的时候,置空更符合垃圾回收器的标准
- 软引用,持有该引用的对象,在内存不足的情况,垃圾回收器才会回收
- 弱引用,很容易被垃圾回收器回收的对象,随时都可能被回收
- 虚引用,用得比较少
二、常用的内存泄露分析工具
Memory Analyzer Tool(MAT)是一款常用的内存分析工具,在Android Studio里面步骤如下:
- 下载MAT桌面版(
https://eclipse.org/mat/downloads.php
) - 从Android Studio获取HPROF文件
- 将Android dalvik格式的.hprof文件转换j2se格式的.hprof文件
- 使用MAT打开转换后的.hprof文件,进入分析界面
LeakCanary是一款检查Android应用程序内存泄露的第三方框架,适合检查Activity、Fragment内存泄露,简单方便:
- 在
app/build.gradle
中加入引用dependencies { debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5' releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5' testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5' }
-
在
Application
中public class MyApplication extends Application { private RefWatcher refWatcher; @Override public void onCreate() { super.onCreate(); refWatcher= setupLeakCanary(); } private RefWatcher setupLeakCanary() { if (LeakCanary.isInAnalyzerProcess(this)) { return RefWatcher.DISABLED; } return LeakCanary.install(this); } public static RefWatcher getRefWatcher(Context context) { MyApplication leakApplication = (MyApplication) context.getApplicationContext(); return leakApplication.refWatcher; } }
三、常见的内存泄露场景
- 资源性对象未关闭。这些资源性对象包括:数据库读写对象、流的读写对象,在使用结束时,应该立即调用它的close()方法将其关闭,然后再置为null
- 注册对象未注销。这些注册对象包括:注册广播对象、注册观察者对象,在引用对象生命周期结束时,应该立即注销掉
- 不再使用的Bitmap对象未调用recycle()方法释放内存。
- 非静态内部类的静态实例长期维持着一个到外部类的引用,阻止外部类被垃圾回收,频繁的创建外部类实例,造成内存泄露。
- Handler临时内存泄露。非静态的Handler内部类可能长期维持着一个到外部类的引用,正确的做法是使用静态内部类代替,同时在引用Handler的Activity或Service生命周期结束后,应该立即移除消息队列中的消息。
- 容器中的对象未清理,造成内存泄露。
- WebView频繁的创建造成你创建泄露。
四、WebView内存泄漏的原因分析及解决办法
Android 5.1及其以上版本,在Activity组件调用WebView加载网页退出后,Activity组件无法被垃圾回收器回收,造成内存泄漏。
原因:可以使用LeakCanary或Android Studio内存监视器查看对象之间的引用关系,因为某个对象没有被释放,同时该对象持有WebView的引用,而WebView又持有Activity的引用,造成Activity退出后被释放。
解决:在Activity组件的onDestroy方法中先将WebView从父容器中移除,然后再调用WebView的onDestroy方法
@Override
protected void onDestroy() {
super.onDestroy();
if (mWebView != null) {
ViewParent parent = mWebView.getParent();
if (parent != null) {
//将WebView从其父容器中移除
((ViewGroup)parent).removeView(mWebView);
}
//移除WebView包含的所有子View
mWebView.removeAllViews();
mWebView.destroy();
mWebView = null;
}
}
Android 5.1 WebView内存泄漏问题及解决
http://blog.csdn.net/u013085697/article/details/53259116
五、使用Handler需要注意的问题
Handler也可能造成临时性的内存泄露,原因在于Handler持有Activity的引用,Message持有Handler的引用,在Message发送MessageQueue时,可能需要等待消息处理,这时候退出Activity,导致对象没有办法被回收,造成内存泄露
解决办法,将Handler声明成一个静态内部类,然后对持有的对象使用弱引用,同时在Activity退出时,清除消息队列中回调或消息
private static class WeakHandler extends Handler{
WeakReference<Context> mContext=null;
public WeakHandler(Context ctx){
mContext=new WeakReference<Context>(ctx);
}
@Override
public void handleMessage(Message msg){
super.handleMessage(msg);
}
}
@Override
public void onDestroy(){
super.onDestroy();
mHandler.removeCallbacksAndMessages(null);
}
你可能感兴趣的文章
转载请注明出处: https://www.teachcourse.cn/2698.html ,谢谢支持!