#内存泄漏针对方案
原文链接https://mp.weixin.qq.com/s/_s88Xjti0YwO4rayKvF5Dg
##一、
###1 针对【静态变量】
在不使用静态变量时 如
sTest = null 至为空
###2 针对【Context】
用到Context 尽量使用 Application 的 Context 避免直接传递 Activity
###3 针对【Activity】
一定要使用Activity 使用弱引用、软引用
//弱引用
WeakReference<Activity> weakReference = new WeakReference<Activity>(this);
Activity activity = weakReference.get();
//软引用
SoftReference<Activity> softReference=new SoftReference<Activity>(this);
Activity activity1 = softReference.get();
##二、 非静态内部类(匿名类)内存泄漏
说明:非静态内部类 (匿名类)默认就持有外部类的引用,当非静态内部类(匿名类)对象的生命周期比外部类对象的生命周期长时,就会导致内存泄露。
-
(1) Handler 的内存泄漏
1.首先,非静态的Handler类会默认持有外部类的引用,包含Activity等。 2.然后,还未处理完的消息(Message)中会持有Handler的引用。 3.还未处理完的消息会处于消息队列中,即消息队列MessageQueue会持有Message的引用。 4.消息队列MessageQueue位于Looper中,Looper的生命周期跟应用一致。 因此,此时的引用关系链是Looper -> MessageQueue -> Message - Handler -> Activity。 所以,这时退出Activity的话,由于存在上述的引用关系,垃圾回收器将无法回收Activity,从而造成内存泄漏。
-
(2) 多线程引起的内存泄漏
我们一般使用匿名类等来启动一个线程,如下:
new Thread(new Runnable() { @Override public void run() { } }).start(); 同样,匿名Thread类里持有了外部类的引用。当Activity退出时,Thread有可能还在后台执行,这时就会发生了内存泄露。
解决方法:
静态内部类
静态内部类不持有外部类的引用,如下:
private static class MyThread extends Thread{
//...
}
Activity退出时,结束线程
同样,这里也是让线程的生命周期跟Activity一致。
其他非静态内部类(匿名类),都可以按照这个套路来:一个是改成静态内部类,另外一个就是内部类的生命周期不要超过外部类。
##三 集合类内存泄漏
说明:集合类添加元素后,将会持有元素对象的引用,导致该元素对象不能被垃圾回收,从而发生内存泄漏。
举个例子:
List<Object> objectList = new ArrayList<>();
for (int i = 0; i < 10; i++) {
Object o = new Object();
objectList.add(o);
o = null;
}
虽然o已经被置空了,但是集合里还是持有Object的引用。
解决方法:
清空集合对象
如下:
objectList.clear();
objectList=null;
##四 未关闭资源对象内存泄漏
该关的全关
1 IO流 File流
InputStream.close();
OutputStream.close();
2 注销广播
unregisterReceiver(receiver);
3 回收Bitmap
Bitmap.recycle();
Bitmap = null;
4 销毁 webView
@Override
protected void onDestroy() {
if( mWebView!=null) {
ViewParent parent = mWebView.getParent();
if (parent != null) {
((ViewGroup) parent).removeView(mWebView);
}
mWebView.stopLoading();
// 退出时调用此方法,移除绑定的服务,否则某些特定系统会报错
mWebView.getSettings().setJavaScriptEnabled(false);
mWebView.clearHistory();
mWebView.clearView();
mWebView.removeAllViews();
mWebView.destroy();
}
super.on Destroy();
}
5 停止动画
属性动画中有一类无限动画,如果Activity退出时不停止动画的话,
动画会一直执行下去。因为动画会持有View的引用,View又持有
Activity,最终Activity就不能给回收掉。只要我们在Activity退
出把动画停掉即可。
animation.cancel();
内存泄漏常用检测工具
###leakcanary
###leakcanary是square开源的一个库,能够自动检测发现内存泄露,其使用也很简单:
在build.gradle中添加依赖:
dependencies {
debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.6.1'
releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.1'
//可选项,如果使用了support包中的fragments
debugImplementation 'com.squareup.leakcanary:leakcanary-support-fragment:1.6.1'
}
如果遇到下面这个问题:
Failed to resolve: com.squareup.leakcanary:leakcanary-android
根目录下的build.gradle添加mavenCentral()即可,如下:
allprojects {
repositories {
google()
jcenter()
mavenCentral()
}
}
###AS 自带工具 Memory Profiler