概念
內(nèi)存泄漏是因為持有對象長期引用,導(dǎo)致對象無法被 GC 回收。
為了避免這種情況,我們可以選擇在對象生命周期結(jié)束的時候,解除綁定,將引用置為空,或者使用弱引用。
例子
- 單例模式導(dǎo)致內(nèi)存泄露
傳入的context為act,但單例的生命周期是app - 非靜態(tài)內(nèi)部類、匿名內(nèi)部類導(dǎo)致內(nèi)存泄露(靜態(tài)變量持有Act,非靜態(tài)內(nèi)部類的靜態(tài)實例 )
它們會隱式的持有外部類的引用,長期持有該引用(比如寫個循環(huán))就會導(dǎo)致內(nèi)存泄漏,使用靜態(tài)內(nèi)部類和弱引用來代替它們。(因為靜態(tài)的內(nèi)部類不會持有外部類的引用) - Handler導(dǎo)致內(nèi)存泄漏
Handler通過發(fā)送Message與主線程交互,Message發(fā)出之后是存儲在MessageQueue中的,有些Message也不是馬上就被處理的。
在Message中存在一個 target,是Handler的一個引用,如果Message在Queue中存在的時間越長,就會導(dǎo)致Handler無法被回收。
如果Handler是非靜態(tài)的,(因為持有外部activity的引用)會導(dǎo)致Activity或者Service不會被回收。
解決方法 :
- 靜態(tài)內(nèi)部類+弱引用
創(chuàng)建一個靜態(tài)Handler內(nèi)部類,然后對Handler持有的對象使用弱引用)
靜態(tài)內(nèi)部類+弱引用。相當(dāng)于activity沒關(guān)閉的時候,act有強(qiáng)弱兩種引用,關(guān)閉的時候,只有弱引用。 - 非靜態(tài)內(nèi)部類+api clean掉message
- 線程造成的內(nèi)存泄漏
執(zhí)行一些長期運行的任務(wù),避免在這些任務(wù)中持有 Activity 對象的引用,如果持有了引用的話,我們應(yīng)該在對象生命周期結(jié)束的時候,釋放引用。 - 資源未關(guān)閉造成的內(nèi)存泄漏
對于使用了BraodcastReceiver,ContentObserver,F(xiàn)ile,Cursor,Stream,Bitmap等資源的使用,應(yīng)該在Activity銷毀時及時關(guān)閉或者注銷,否則這些資源將不會被回收,造成內(nèi)存泄漏。
LeakCanary
LeakCanary的內(nèi)存泄露提示一般會包含三個部分:
第一部分(LeakSingle類的sInstance變量)引用第二部分(LeakSingle類的mContext變量), 導(dǎo)致第三部分(MainActivity類的實例instance)泄露.
Java的GC內(nèi)存回收機(jī)制

當(dāng)我們向上尋找,一直尋找到GC Root的時候,此對象不會進(jìn)行回收,例如,一個Activity。那么如果我們向上尋找,直到找到GC Root對象的時候,就說明它是不可以回收的,例如,我定義了一個int a;但是這個數(shù)據(jù),我整個頁面或者說整個項目都沒有用到,則這個對象會被GC掉。
GC的引用點
java棧中引用的對象
方法靜態(tài)引用的對象
方法常量引用的對象
Native中JNI引用的對象
Thread——“活著的”線程
內(nèi)存溢出

瞬間大內(nèi)存:圖片加載
內(nèi)存泄漏和內(nèi)存溢出區(qū)別
內(nèi)存溢出是指程序在申請內(nèi)存的時候,沒有足夠的內(nèi)存可以分配,導(dǎo)致Out Of Memory錯誤,也就是OOM。
內(nèi)存泄漏:對象都有生命周期的,在生命周期完成之后,就該被垃圾回收和釋放,如果得不到及時的釋放,就會一直占用內(nèi)存,造成內(nèi)存泄漏。隨著內(nèi)存泄漏的堆積,可能導(dǎo)致oom。