本文主要總結(jié)Android開發(fā)中發(fā)生的內(nèi)存泄漏場景荤崇,發(fā)生的原因,以及解決方案杭攻。
目錄
- Java內(nèi)部類隱式持有外部類
- Java匿名內(nèi)部類隱式持有外部類
- Android的Window類持有了activity
- [LeakCanary提示
policy.HwPhoneWindow$1.this$0
的泄漏](#LeakCanary提示policy.HwPhoneWindow$1.this$0
的泄漏) - [Android InputMethodManager](#Android InputMethodManage)
java的gc檢查內(nèi)存回收時家夺,使用有向圖機制钝侠,及檢查一個或一組對象的可達性。如果是不可達狀態(tài)酸舍,則將該對象從內(nèi)存中回收帅韧,所謂不可達狀態(tài),也就是一個對象不被任何引用所指向或者叫持有啃勉。
另外忽舟,java的循環(huán)引用不同于oc或者c++,當(dāng)一組對象中只包含互相的引用,而沒有來自它們外部的引用(例如有兩個對象A和B互相持有引用淮阐,但沒有任何外部對象持有指向A或B的引用)叮阅,這仍然屬于不可到達,同樣會被GC回收泣特。
注意:
在Android開發(fā)過程中浩姥,activity會天然的被window對象所應(yīng)用,所以在activity中與其他類循環(huán)應(yīng)用時状您,盡量使用弱引用模式勒叠,
Java內(nèi)部類隱式持有外部類
常見于
ViewHolder
或者new Handler
,new Listener
等情況
案例如下:
public class MainActivity extends AppCompatActivity {
private TestResource mResource = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(mManager == null){
mManager = new TestResource();
}
//...
}
class TestResource {
//...
}
}
分析:
如果TestResource
我們執(zhí)行了耗時操作,在銷毀Activity時膏孟,由于testResource隱藏性的指向了Activity的實例眯分,所以在testResource會執(zhí)行結(jié)束時,不會銷毀Activity柒桑,發(fā)生了內(nèi)存泄漏弊决。
解決方案:
內(nèi)部類增加static前綴,這樣就不會隱式指向外部類了幕垦。增加static前綴也相當(dāng)了新建一個java文件
static class TestResource {
//...
}
}
Java匿名內(nèi)部類隱式持有外部類
該案例同上書問題一樣丢氢,我們?yōu)榱朔奖銜诖罅渴褂媚涿麅?nèi)部類,而不是重新定義內(nèi)部類先改,比如在在Thread或者事件監(jiān)聽場景中疚察。
新建一個線程
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
new Thread(new Runnable(){
@Override
public void run() {
}
}).start();
}
分析:
此時如果發(fā)生在Activity類,比我們可以看到在run()函數(shù)可以直接調(diào)用activity的成員變量仇奶,說明這個Runnable匿名內(nèi)部類已經(jīng)持有了Activity的實例貌嫡,當(dāng)Runnable執(zhí)行耗時操作時,Activity就銷毀不掉了该溯。
解決方案:
匿名內(nèi)部類提出來岛抄,作為成員變量并增加static前綴,就解除了與外外部類的關(guān)系
static Runnable runnable = new Runnable() {
@Override
public void run() {
}
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
new Thread(runnable).start();
}
LeakCanary提示policy.HwPhoneWindow$1.this$0
的泄漏
最新在華為手機GEM=703L android6.0發(fā)現(xiàn)的問題狈茉,在
AsyncTask
執(zhí)行ProgressDialog
的顯示或隱藏夫椭,然后退出activity會發(fā)生泄漏。泄漏提示
GC ROOT com.android.internal.policy.HwPhoneWindow$1.this$0
分析過程太長了氯庆,轉(zhuǎn)移到新的文章
LeakCanary提示policy.HwPhoneWindow$1.this$0
的泄漏分析
Android InputMethodManager
這中情況導(dǎo)致的內(nèi)存目前還在研究中蹭秋,先貼出大家的討論
Android InputMethodManager 導(dǎo)致的內(nèi)存泄露及解決方案
[Android][Memory Leak] InputMethodManager內(nèi)存泄露現(xiàn)象及解決