Android內存泄露之非靜態內部類|匿名內部類

原文: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個思路:

  • 嚴格保證程序邏輯
  1. 在銷燬Activity的時候結束掉在執行的後臺線程。線程結束了,就等於切斷了與外部類關聯的線。
  2. 使用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 ......;
       }
   }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章