首先我們先談?wù)刯ava對象回收條件是什么?
當沒有任何引用指向該對象的時候。
(存在兩種情況:1.該對象的最后一個引用指向了另一個對象或null。 2.該對象的最后一個引用的作用域結(jié)束。)
內(nèi)存泄漏是什么?
內(nèi)存泄漏通俗來講就是長生命周期對象強引用了短生命周期對象,在短生命周期對象想回收時,強生命周期還是不對其解除引用。這時候短生命周期對象就不會被回收,但我們的想法是以后不會用這個短生命周期對象了,這時候該對象就是泄漏的垃圾對象了。當這些對象泄漏的多了,就會占用大量內(nèi)存,最終結(jié)果也就造成oom了。
下面我就用個簡單的例子,來看看是不是這樣的
public class Main2Activity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
Log.i("----------", "onCreate: activity_main2");
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}

1.png

2.png
上面兩張圖我們很容易看出,我打開并退出了5次Main2Activity,然后用內(nèi)存分析工具強制gc后Main2Activity實例數(shù)依然是5個,此時就是內(nèi)存泄漏了。而內(nèi)存泄漏的原因就是Thread對象持有了Runnable對象(和他持有Runnable關(guān)系不大),Runnable對象中的run方法又間接持有了Main2Activity(這才是主要原因),然而這個Runnable對象中run方法短期又執(zhí)行不完,結(jié)果就造成Runnable對象不會回收,Main2Activity也無法回收。
問題:此時Thread對象有沒有回收?
答案:沒有回收。
看下源碼就知道原因了:
public class Thread implements Runnable {
private Runnable target;
@Override
public void run() {
if (target != null) {
target.run();
}
}
}
我們可以看出Thread對象中也實現(xiàn)了Runnable接口,然后thread中run方法中調(diào)用了target.run();而這個target就是我們剛剛在Main2Activity中實現(xiàn)的Runnable對象。當我們開啟一個線程之后,最終它會在那個線程中運行這個run方法,然而target.run執(zhí)行結(jié)束前,thread的run方法肯定也結(jié)束不了了,就造成thread也無法回收(從另一個角度理解:thread中的run方法肯定也是持有thread對象的引用,所以這些方法執(zhí)行完畢前這些被方法引用的對象也自然無法回收了)
最后再推薦一個很多人都知道的一個Android內(nèi)存泄漏檢查框架,leakcanary,我們也可以用他來檢查內(nèi)存泄漏。