android 隨筆之內存泄漏

1.單例造成的內存泄漏

由于單例的靜態(tài)特性使得其生命周期和應用的生命周期一樣長,如果一個對象已經不再需要使用了梁只,而單例對象還持有該對象的引用埃脏,就會使得該對象不能被正常回收彩掐,從而導致了內存泄漏。

2.非靜態(tài)內部類創(chuàng)建靜態(tài)實例造成的內存泄漏

例如旁壮,有時候我們可能會在啟動頻繁的Activity中谐檀,為了避免重復創(chuàng)建相同的數據資源,可能會出現如下寫法:


  private static TestResource mResource = null;

  @Override

  protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

      setContentView(R.layout.activity_main);

      if(mResource == null){

          mResource = new TestResource();

      }

      //...

  }

class TestResource {

  //...

  }

}

這樣在Activity內部創(chuàng)建了一個非靜態(tài)內部類的單例麦撵,每次啟動Activity時都會使用該單例的數據溃肪。雖然這樣避免了資源的重復創(chuàng)建,但是這種寫法卻會造成內存泄漏羔沙。因為非靜態(tài)內部類默認會持有外部類的引用厨钻,而該非靜態(tài)內部類又創(chuàng)建了一個靜態(tài)的實例坚嗜,該實例的生命周期和應用的一樣長诗充,這就導致了該靜態(tài)實例一直會持有該Activity的引用,從而導致Activity的內存資源不能被正车螅回收茎匠。

解決方法:將該內部類設為靜態(tài)內部類或將該內部類抽取出來封裝成一個單例,如果需要使用Context抓狭,就使用Application的Context造烁。

3.Handler造成的內存泄漏

示例:創(chuàng)建匿名內部類的靜態(tài)對象


  private final Handler handler = new Handler() {

    @Override

  public void handleMessage(Message msg) {

        // ...

    }

  };

  @Override

  protected void onCreate(Bundle savedInstanceState) {

      super.onCreate(savedInstanceState);

      setContentView(R.layout.activity_main);

      new Thread(new Runnable() {

          @Override

          public void run() {

            // ...

            handler.sendEmptyMessage(0x123);

          }

    });

  }

}

1惭蟋、從Android的角度

當Android應用程序啟動時药磺,該應用程序的主線程會自動創(chuàng)建一個Looper對象和與之關聯的MessageQueue。當主線程中實例化一個Handler對象后木缝,它就會自動與主線程Looper的MessageQueue關聯起來围辙。所有發(fā)送到MessageQueue的Message都會持有Handler的引用,所以Looper會據此回調Handle的handleMessage()方法來處理消息矫俺。只要MessageQueue中有未處理的Message掸冤,Looper就會不斷的從中取出并交給Handler處理。另外铅匹,主線程的Looper對象會伴隨該應用程序的整個生命周期饺藤。

2流礁、 Java角度

在Java中舰始,非靜態(tài)內部類和匿名類內部類都會潛在持有它們所屬的外部類的引用,但是靜態(tài)內部類卻不會枕稀。

對上述的示例進行分析谜嫉,當MainActivity結束時,未處理的消息持有handler的引用哆档,而handler又持有它所屬的外部類也就是MainActivity的引用住闯。這條引用關系會一直保持直到消息得到處理,這樣阻止了MainActivity被垃圾回收器回收比原,從而造成了內存泄漏量窘。

解決方法:將Handler類獨立出來或者使用靜態(tài)內部類,這樣便可以避免內存泄漏蚌铜。

4.線程造成的內存泄漏

示例:AsyncTask和Runnable

AsyncTask和Runnable都使用了匿名內部類冬殃,那么它們將持有其所在Activity的隱式引用。如果任務在Activity銷毀之前還未完成造壮,那么將導致Activity的內存資源無法被回收耳璧,從而造成內存泄漏。

解決方法:將AsyncTask和Runnable類獨立出來或者使用靜態(tài)內部類旨枯,這樣便可以避免內存泄漏攀隔。

5.資源未關閉造成的內存泄漏

對于使用了BraodcastReceiver栖榨,ContentObserver明刷,File,Cursor辈末,Stream,Bitmap等資源轰枝,應該在Activity銷毀時及時關閉或者注銷组去,否則這些資源將不會被回收,從而造成內存泄漏诚撵。

1)比如在Activity中register了一個BraodcastReceiver键闺,但在Activity結束后沒有unregister該BraodcastReceiver艾杏。

2)資源性對象比如Cursor盅藻,Stream、File文件等往往都用了一些緩沖氏淑,我們在不使用的時候,應該及時關閉它們假残,以便它們的緩沖及時回收內存缭贡。它們的緩沖不僅存在于 java虛擬機內,還存在于java虛擬機外辉懒。如果我們僅僅是把它的引用設置為null阳惹,而不關閉它們,往往會造成內存泄漏眶俩。

3)對于資源性對象在不使用的時候莹汤,應該調用它的close()函數將其關閉掉,然后再設置為null颠印。在我們的程序退出時一定要確保我們的資源性對象已經關閉纲岭。

4)Bitmap對象不在使用時調用recycle()釋放內存抹竹。2.3以后的bitmap應該是不需要手動recycle了,內存已經在java層了止潮。

6.使用ListView時造成的內存泄漏

初始時ListView會從BaseAdapter中根據當前的屏幕布局實例化一定數量的View對象窃判,同時ListView會將這些View對象緩存起來喇闸。當向上滾動ListView時袄琳,原先位于最上面的Item的View對象會被回收,然后被用來構造新出現在下面的Item仅偎。這個構造過程就是由getView()方法完成的跨蟹,getView()的第二個形參convertView就是被緩存起來的Item的View對象(初始化時緩存中沒有View對象則convertView是null)。

構造Adapter時橘沥,沒有使用緩存的convertView窗轩。

解決方法:在構造Adapter時,使用緩存的convertView座咆。

7.集合容器中的內存泄露

我們通常把一些對象的引用加入到了集合容器(比如ArrayList)中痢艺,當我們不需要該對象時,并沒有把它的引用從集合中清理掉介陶,這樣這個集合就會越來越大堤舒。如果這個集合是static的話,那情況就更嚴重了哺呜。

解決方法:

在退出程序之前舌缤,將集合里的東西clear,然后置為null某残,再退出程序国撵。

8.WebView造成的泄露

當我們不要使用WebView對象時,應該調用它的destory()函數來銷毀它玻墅,并釋放其占用的內存介牙,否則其長期占用的內存也不能被回收,從而造成內存泄露澳厢。

解決方法:

為WebView另外開啟一個進程环础,通過AIDL與主線程進行通信,WebView所在的進程可以根據業(yè)務的需要選擇合適的時機進行銷毀剩拢,從而達到內存的完整釋放线得。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市徐伐,隨后出現的幾起案子框都,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件魏保,死亡現場離奇詭異熬尺,居然都是意外死亡,警方通過查閱死者的電腦和手機谓罗,發(fā)現死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門粱哼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人檩咱,你說我怎么就攤上這事揭措。” “怎么了刻蚯?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵绊含,是天一觀的道長。 經常有香客問我炊汹,道長躬充,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任讨便,我火速辦了婚禮充甚,結果婚禮上,老公的妹妹穿的比我還像新娘霸褒。我一直安慰自己伴找,他們只是感情好,可當我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布废菱。 她就那樣靜靜地躺著技矮,像睡著了一般。 火紅的嫁衣襯著肌膚如雪殊轴。 梳的紋絲不亂的頭發(fā)上穆役,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天,我揣著相機與錄音梳凛,去河邊找鬼。 笑死梳杏,一個胖子當著我的面吹牛韧拒,可吹牛的內容都是我干的。 我是一名探鬼主播十性,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼叛溢,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了劲适?” 一聲冷哼從身側響起楷掉,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎霞势,沒想到半個月后烹植,有當地人在樹林里發(fā)現了一具尸體斑鸦,經...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年草雕,在試婚紗的時候發(fā)現自己被綠了巷屿。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡墩虹,死狀恐怖嘱巾,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情诫钓,我是刑警寧澤旬昭,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站菌湃,受9級特大地震影響问拘,放射性物質發(fā)生泄漏。R本人自食惡果不足惜慢味,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一场梆、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧纯路,春花似錦或油、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至叫编,卻和暖如春辖佣,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背搓逾。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工卷谈, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人霞篡。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓世蔗,卻偏偏與公主長得像,于是被迫代替她去往敵國和親朗兵。 傳聞我的和親對象是個殘疾皇子污淋,可洞房花燭夜當晚...
    茶點故事閱讀 44,713評論 2 354