【拒絕一問就懵】之不可忽視的內存泄露

背景介紹

內存泄漏一種狀況是一塊內存沒有引用指向它,卻沒被回收,這種狀況已經由Java虛擬機的 GC緩存

幫助咱們處理好了,見 【拒絕一問就懵】之你多少要懂點內存回收機制;另外一種屬於 邏輯內存泄漏,即一個對象已經再也不被使用了,但它仍然被另外一個被使用中的對象所持有,致使該對象所佔用的內存塊不能被回收。bash

少部分內存泄漏看不出有什麼影響,但若是大量發生,將會明顯減小可用內存,致使頻繁GC,運行緩慢,嚴重時將容易引起OutOfMemoryErrorapp

Android中常見的內存泄漏

集合引起的泄漏

一些對象緩存到集合中,當它不在被使用時,沒有從集合中移除,就形成了泄漏。異步

Activity中的泄漏

一個Activity中的Context一般會被不少地方引用,若是在Activity執行了onDestory()後這些引用沒有被置空,將會致使Activity沒法被回收。而Activity中依賴了很對對象,這些對象將都不能被回收,因此必定要十分當心Activity的泄漏。如下幾種常見的狀況須要注意:ide

  • 當建立一個對象,該對象須要Context做爲參數時。當該對象在Activity執行了onDestory()後仍然可到達,那麼它持有的Activity就沒法被回收。
  • 使用匿名內部類Handler時。Handler會間接的持有外部Activity的引用,當Activity執行了onDestory()後,若Handler中仍然有消息在MessageQueue中,那麼該Handler就不能被釋放,也就意味着Activity也不會被釋放。解決方法:
    • 須要在onDestory()完成前確保Handler沒有執行yan shi延時任務,沒有被其餘地方引用。同時清理Handler中全部任務,調用removeCallbacksAndMessages(null);,該方法參數爲空時會移除因此的CallBack和Message。
    • 另外一種方法是自定義一個靜態內部Handler,讓它持有的Activity爲弱引用。
    static class MyHandler extends Handler {
          private final WeakReference<Activity> mActivity;
          public MyHandler(Activity activity) {
              mActivity = new WeakReference<Activity>(activity);
          }
          @Override
          public void handleMessage(Message msg) {
              System.out.println(msg);
              if (mActivity.get() == null) {
                  return;
              }
              mActivity.get().todo();
          }
      }
    複製代碼
  • 在異步任務中引用Activity或Context,而沒有在Activity銷燬前中止線程,就會致使Activity的泄漏。
  • 內部類、匿名內部類會持有外部類的實例,因此在Activity中使用內部類或匿名內部類,而且將該類建立的對象傳遞給其餘對象,若該對象在Activity以外被引用,或是在仍在進行的異步任務中,那麼Activity將不能釋放。

Bitmap引起的內存泄漏

Bitmap是引用中佔用內存的大戶,在使用時必定要十分注意。當Bitmap不用時,應該及時調用recycle()釋放其申請的內存。post

異步任務引起的泄漏

異步任務若是在它應該中止的時候沒有中止,那它自己及它所依賴的對象將都不能被正確的釋放。好比上面提到的Activity中的異步任務。ui

好比在Activity中這樣來開啓一個異步任務:spa

new Thread(()->{
  // doSomething with long-time 
}).start();
複製代碼

那麼,在Activity已經finish()了,但異步任務中的Runnable還被持有,而且因爲是屬於Activity的匿名內部類,因此會致使Activity的內存不能及時回收。線程

總結

因爲系統內存資源有限,因此咱們須要儘可能避免 內存泄漏,以保證程序可以流暢運行。code

  • 因爲Activity泄漏將會連帶大量的對象一塊兒泄漏,因此在Activity中寫代碼應該特別注意Handler、內部類及匿名內部類,還有Context不能隨便傳遞。
  • 使用異步任務時必定要明確其做用範圍,在應該中止的時候記得中止。
  • Bitmap佔用內存一般較大,因此在使用完後及時釋放十分重要。
  • 此外,在傳遞參數到單例中時,也須要謹慎。
相關文章
相關標籤/搜索