原文:https://blog.csdn.net/u012982629/article/details/82770282
知識點:
非靜態內部類|匿名內部類 默認持有外部類的引用
什麼是內存泄露?
Java使用有向圖機制,通過GC自動檢查內存中的對象(什麼時候檢查由虛擬機決定),如果GC發現一個或一組對象爲不可到達狀態,則將該對象從內存中回收。也就是說,一個對象不被任何引用所指向,則該對象會在被GC發現的時候被回收;另外,如果一組對象中只包含互相的引用,而沒有來自它們外部的引用(例如有兩個對象A和B互相持有引用,但沒有任何外部對象持有指向A或B的引用
),這仍然屬於不可到達,同樣會被GC回收。
首先我們儲備一個知識點
在Java中非靜態內部類 | 匿名內部類都默認持有外部類的引用,使用不當的話會使外部類一直被某對象持有引用,從而在其該被GC回收時卻不被回收,也最終導致了內存泄漏。
我們經常用到的AsyncTask、Runnable、Handler、Thread等類,在採用非靜態內部類|匿名內部類的方式使用的話,都會隱式地持有外部類的引用。
其原因其實也好理解的,如果不是隱式地持有外部類的引用,我們怎麼可以在內部任意使用外部類的變量、方法呢?
出現內存泄漏的原因大都是在Activity已經銷燬的時候,其還有在執行未關閉的後臺線程或MessageQueue(消息隊列)中有延時待分發處理的Message,Message中又持有Handler實例,Handler又持有Activity實例。
解決方案有2個思路:
- 嚴格保證程序邏輯
- 在銷燬Activity的時候結束掉在執行的後臺線程。線程結束了,就等於切斷了與外部類關聯的線。
- 使用Handler.postDelayed( new Runnable(),xxx)方式的話,直接調用Handler的
removeCallbacksAndMessages
(null)方法,移除回收消息隊列的消息即可。
- 採用靜態內部類+弱引用(WeakReference)持有外部類實例
private static class MyHandler extends Handler {
WeakReference<Activity > mActivityReference;
MyHandler(Activity activity) {
mActivityReference= new WeakReference<Activity>(activity);
}
@Override
public void handleMessage(Message msg) {
final Activity activity = mActivityReference.get();
if (activity != null) {
activity.xxx ......;
}
}
}