您的位置:首页 > 移动开发 > Android开发

Android常见内存泄漏和LeakCanary的使用

2017-01-08 23:49 363 查看
App有内存泄漏就是埋了一颗定时炸弹, 累积多了终将导致OOM. 下面列举一些常见导致内存泄漏的代码.

未注销导致的内存泄漏

使用了广播, EventBus等等, 会导致Activity无法被GC回收

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_common);
EventBus.getDefault().register(this);
}

@Subscribe
public void onEvent(MessageEvent msg) {

}

@Override
protected void onDestroy() {
super.onDestroy();
//未移除注册的EventBus
//        EventBus.getDefault().unregister(this);
}


非静态内部类使用不当导致的内存泄漏

非静态内部类会持有外部类引用, 如果Activity中包含了静态的内部类成员就会导致内存泄漏

private static InnerClass mInnerClass;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_common);
mInnerClass = new InnerClass();
}

//非静态内部类持有外部类引用
public class InnerClass {
private String msg;

public InnerClass() {
}

}


匿名类使用不当导致的内存泄漏

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_common);
//匿名类持有外部类引用
new AsyncTask<Void, Void, Void>() {

@Override
protected Void doInBackground(Void... params) {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return null;
}
}.execute();
}


工具类使用不当导致的内存泄漏

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_common);
String s = Util.getInstance(this).doSomething();
}


public class Util {
private volatile static Util instance;
private static Context mContext;

private Util(Context context) {
mContext = context;
}
//传进来的context被静态持有
public static Util getInstance(Context context) {
if (instance == null) {
synchronized (Util.class) {
if (instance == null) {
instance = new Util(context);
}
}
}
return instance;
}

public static String doSomething() {
String string = mContext.getResources().getString(R.string.app_name);
return string;
}
}


写Util的时需要Context的时候, 判断一下, 如果可以用ApplicationContext优先使用.

可以用ApplicationContext的情况下在Application里面加上一个getInstance()方法, 就不用传Context进来了.

public class App extends Application {
private static App instance;

public static App getInstance() {
return instance;
}

@Override
public void onCreate() {
super.onCreate();
instance = this;
}
}


线程使用不当导致的内存泄漏

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_common);
//Activity实例被Runnable持有, Runnable传入l一个异步线程,
// 此线程和此Acitivity生命周期不一致的时候,就造成了Activity的泄露。
new Thread(new Runnable() {
@Override
public void run() {
while (true) ;
}
}).start();
}


Handle使用不当导致的内存泄漏

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

}
};

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_common);
//Handler 为非静态内部类,它会持有外部类的引用
mLeakyHandler.postDelayed(new Runnable() {
@Override
public void run() {
//doSomething
}
}, 1000 * 20);
}


静态集合使用不当导致的内存泄漏

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_common);
ActivityCollector.addActivity(this);
}

@Override
protected void onDestroy() {
super.onDestroy();
//静态集合没有移除元素
//        ActivityCollector.removeActivity(this);
}


public class ActivityCollector {

public static List<Activity> activities = new ArrayList<Activity>();

public static void addActivity(Activity activity) {
activities.add(activity);
}

public static void removeActivity(Activity activity) {
activities.remove(activity);
}
}


使用弱引用避免内存泄漏

在 Activity 中避免使用非静态内部类,比如上面我们将 Handler 声明为静态的,则其存活期跟 Activity 的生命周期就无关了。同时通过弱引用的方式引入 Activity,避免直接将 Activity 作为 context 传进去

public class WeakReferenceActivity extends AppCompatActivity {

//将 Handler 声明为静态 没有了Activity的引用, 无法直接引用其变量或方法,
// 使用弱引用WeakReference来解决这个问题
private static class DBHandler extends Handler {

//弱引用, 而不是使用外部类this或者传进来
private final WeakReference<WeakReferenceActivity> mActivity;

public DBHandler(WeakReferenceActivity activity) {
mActivity = new WeakReference<>(activity);
}

@Override
public void handleMessage(Message msg) {
WeakReferenceActivity activity = mActivity.get();
if (activity != null) {
Toast.makeText(activity, "what: " + msg.what, Toast.LENGTH_SHORT).show();
}
}

}

private final DBHandler mHandler = new DBHandler(this);

private static final Runnable sRunnable = new Runnable() {
@Override
public void run() {
Toast.makeText(App.getInstance(), "sRunnable run()", Toast.LENGTH_SHORT).show();
}
};

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_weak_reference);
mHandler.postDelayed(sRunnable, 1000 * 20);
}

public void onClick(View view) {
mHandler.sendEmptyMessage(new Random().nextInt(10));
}
}


LeakCanary的使用

build.gradle dependencies{…}添加

//https://github.com/square/leakcanary
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 App extends Application {
private static App instance;
private static RefWatcher sRefWatcher;

public static RefWatcher getRefWatcher() {
return sRefWatcher;
}

public static App getInstance() {
return instance;
}

@Override
public void onCreate() {
super.onCreate();
if (LeakCanary.isInAnalyzerProcess(this)) {
// This process is dedicated to LeakCanary for heap analysis.
// You should not init your app in this process.
return;
}
sRefWatcher = LeakCanary.install(this);
// Normal app init code...
instance = this;
}
}


AndroidManifest.xml

<application
android:name="yourApp"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
</application>


检测Fragment内存泄漏

public class LeakFragment extends Fragment {

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.activity_common, container, false);
return view;
}

@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
new Thread(new Runnable() {
@Override
public void run() {
while (true) ;
}
}).start();
}

@Override
public void onDestroy() {
super.onDestroy();
//onDestroy中添加
App.getRefWatcher().watch(this);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: