Activity是如何泄漏的

只要非靜態(tài)的匿名類對象沒有被回收奏司,MainActivity就不會被回收,MainActivity所關聯(lián)的資源和視圖都不會被回收樟插,發(fā)生比較嚴重的內存泄漏韵洋。

/**
 * Example illustrating how threads persist across configuration
 * changes (which cause the underlying Activity instance to be
 * destroyed). The Activity context also leaks because the thread
 * is instantiated as an anonymous class, which holds an implicit
 * reference to the outer Activity instance, therefore preventing
 * it from being garbage collected.
 */
public class MainActivity extends Activity {
 
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    exampleOne();
  }
 
  private void exampleOne() {
    newThread() {//匿名內部類,非靜態(tài)的匿名類會持有外部類的一個隱式引用
      @Override
      publicvoid run() {
        while(true) {
          SystemClock.sleep(1000);
        }
      }
    }.start();
  }
}

要解決MainActivity的內存泄漏問題黄锤,只需把非靜態(tài)的Thread匿名類定義成靜態(tài)的內部類就行了(靜態(tài)的內部類不會持有外部類的一個隱式引用):

/**
 * This example avoids leaking an Activity context by declaring the
 * thread as a private static inner class, but the threads still
 * continue to run even across configuration changes. The DVM has a
 * reference to all running threads and whether or not these threads
 * are garbaged collected has nothing to do with the Activity lifecycle.
 * Active threads will continue to run until the kernel destroys your
 * application's process.
 */
public class MainActivity extends Activity {
 
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    exampleTwo();
  }
 
  private void exampleTwo() {
    new MyThread().start();
  }
 
  private static class MyThread extends Thread {
    @Override
    public void run() {
      while(true) {
        SystemClock.sleep(1000);
      }
    }
  }
}

現(xiàn)在新創(chuàng)建的Thread不會持有MainActivity的一個隱式引用搪缨,當手機屏幕旋轉時不會阻止垃圾回收器對舊MainActivity的回收工作。

Thread是如何泄漏的

在提到的第二個問題中鸵熟,一旦一個新的Activity創(chuàng)建副编,那么就有一個Thread永遠得不到清理回收,發(fā)生內存泄漏流强。Threads在Java中是GC roots;意味著 Dalvik Virtual Machine (DVM) 會為所有活躍的threads在運行時系統(tǒng)中保持一個硬引用痹届,這會導致threads一直處于運行狀態(tài),垃圾收集器將永遠不可能回收它打月。出于這個原因短纵,我們應當為threads添加一個結束的邏輯,如下代碼所示

/**
 * Same as example two, except for this time we have implemented a
 * cancellation policy for our thread, ensuring that it is never
 * leaked! onDestroy() is usually a good place to close your active
 * threads before exiting the Activity.
 */
publicclass MainActivity extends Activity {
  privateMyThread mThread;
 
  @Override
  protectedvoid onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    exampleThree();
  }
 
  privatevoid exampleThree() {
    mThread = new MyThread();
    mThread.start();
  }
 
  /**
   * Static inner classes don't hold implicit references to their
   * enclosing class, so the Activity instance won't be leaked across
   * configuration changes.
   */
  privatestatic class MyThread extends Thread {
    privateboolean mRunning = false;
 
    @Override
    publicvoid run() {
      mRunning = true;
      while(mRunning) {
        SystemClock.sleep(1000);
      }
    }
 
    publicvoid close() {
      mRunning = false;
    }
  }
 
  @Override
  protectedvoid onDestroy() {
    super.onDestroy();
    mThread.close();
  }
}

在上述的代碼中僵控,當Activity結束銷毀時在onDestroy()方法中結束了新創(chuàng)建的線程香到,保證了thread不會發(fā)生泄漏。但是如果你想在手機配置發(fā)生改變時保持原有的線程而不重新創(chuàng)建的話,你可以考慮使用fragment來保留原有的線程悠就,以備下一次使用具體做法可以參考我之前的一篇文章 http://blog.csdn.net/tu_bingbing/article/details/9274289千绪,關于這方面 APIdemos 中也做了相關的實現(xiàn)。

結論

在Android中梗脾,長時間運行的任務和Acyivity生命周期進行協(xié)調會有點困難荸型,如果你不加以小心的話會導致內存泄漏。關于如何處理這個棘手的問題炸茧,下面有幾個基本的技巧供參考

  1瑞妇、使用靜態(tài)內部類/匿名類,不要使用非靜態(tài)內部類/匿名類.非靜態(tài)內部類/匿名類會隱式的持有外部類的引用梭冠,外部類就有可能發(fā)生泄漏辕狰。而靜態(tài)內部類/匿名類不會隱式的持有外部類引用,外部類會以正常的方式回收控漠,如果你想在靜態(tài)內部類/匿名類中使用外部類的屬性或方法時蔓倍,可以顯示的持有一個弱引用。

 2盐捷、不要以為Java永遠會幫你清理回收正在運行的threads.在上面的代碼中偶翅,我們很容易誤以為當Activity結束銷毀時會幫我們把正在運行的thread也結束回收掉,但事情永遠不是這樣的碉渡!Java threads會一直存在聚谁,只有當線程運行完成或被殺死掉,線程才會被回收滞诺。所以我們應該養(yǎng)成為thread設置退出邏輯條件的習慣形导。

 3、適當?shù)目紤]下是否應該使用線程.Android應用框架設計了許多的類來簡化執(zhí)行后臺任務铭段,我們可以使用與Activity生命周期相關聯(lián)的Loaders來執(zhí)行簡短的后臺查詢任務骤宣。如果一個線程不依賴與Activity秦爆,我們還可以使用Service來執(zhí)行后臺任務序愚,然后用BroadcastReceiver來向Activity報告結果。另外需要注意的是本文討論的thread同樣使用于AsyncTasks等限,AsyncTask同樣也是由線程來實現(xiàn)爸吮,只不過使用了Java5.0新增并發(fā)包中的功能,但同時需要注意的是根據(jù)官方文檔所說望门,AsyncTask適用于執(zhí)行一些簡短的后臺任務
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末形娇,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子筹误,更是在濱河造成了極大的恐慌桐早,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,589評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異哄酝,居然都是意外死亡友存,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評論 3 396
  • 文/潘曉璐 我一進店門陶衅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來屡立,“玉大人,你說我怎么就攤上這事搀军∨蚶” “怎么了?”我有些...
    開封第一講書人閱讀 165,933評論 0 356
  • 文/不壞的土叔 我叫張陵罩句,是天一觀的道長焚刺。 經(jīng)常有香客問我,道長的止,這世上最難降的妖魔是什么檩坚? 我笑而不...
    開封第一講書人閱讀 58,976評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮诅福,結果婚禮上匾委,老公的妹妹穿的比我還像新娘。我一直安慰自己氓润,他們只是感情好赂乐,可當我...
    茶點故事閱讀 67,999評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著咖气,像睡著了一般挨措。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上崩溪,一...
    開封第一講書人閱讀 51,775評論 1 307
  • 那天浅役,我揣著相機與錄音,去河邊找鬼伶唯。 笑死觉既,一個胖子當著我的面吹牛,可吹牛的內容都是我干的乳幸。 我是一名探鬼主播瞪讼,決...
    沈念sama閱讀 40,474評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼粹断!你這毒婦竟也來了符欠?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,359評論 0 276
  • 序言:老撾萬榮一對情侶失蹤瓶埋,失蹤者是張志新(化名)和其女友劉穎希柿,沒想到半個月后诊沪,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,854評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡曾撤,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,007評論 3 338
  • 正文 我和宋清朗相戀三年娄徊,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片盾戴。...
    茶點故事閱讀 40,146評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡寄锐,死狀恐怖,靈堂內的尸體忽然破棺而出尖啡,到底是詐尸還是另有隱情橄仆,我是刑警寧澤,帶...
    沈念sama閱讀 35,826評論 5 346
  • 正文 年R本政府宣布衅斩,位于F島的核電站盆顾,受9級特大地震影響,放射性物質發(fā)生泄漏畏梆。R本人自食惡果不足惜您宪,卻給世界環(huán)境...
    茶點故事閱讀 41,484評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望奠涌。 院中可真熱鬧宪巨,春花似錦、人聲如沸溜畅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,029評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽慈格。三九已至怠晴,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間浴捆,已是汗流浹背蒜田。 一陣腳步聲響...
    開封第一講書人閱讀 33,153評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留选泻,地道東北人芝发。 一個月前我還...
    沈念sama閱讀 48,420評論 3 373
  • 正文 我出身青樓兽赁,卻偏偏與公主長得像悠栓,于是被迫代替她去往敵國和親痘昌。 傳聞我的和親對象是個殘疾皇子茂嗓,可洞房花燭夜當晚...
    茶點故事閱讀 45,107評論 2 356

推薦閱讀更多精彩內容

  • Android 內存管理的目的 內存管理的目的就是讓我們在開發(fā)中怎么有效的避免我們的應用出現(xiàn)內存泄漏的問題餐茵。簡單粗...
    晨光光閱讀 1,294評論 1 4
  • 1.ios高性能編程 (1).內層 最小的內層平均值和峰值(2).耗電量 高效的算法和數(shù)據(jù)結構(3).初始化時...
    歐辰_OSR閱讀 29,395評論 8 265
  • 所有知識點已整理成app app下載地址 J2EE 部分: 1.Switch能否用string做參數(shù)? 在 Jav...
    侯蛋蛋_閱讀 2,442評論 1 4
  • 內存管理的目的就是讓我們在開發(fā)中怎么有效的避免我們的應用出現(xiàn)內存泄漏的問題述吸。內存泄漏大家都不陌生了忿族,簡單粗俗的講锣笨,...
    宇宙只有巴掌大閱讀 2,363評論 0 12
  • 時間蒼老了許多 以前错英,心里總住著一個小男孩。不管遇到什么隆豹,都能坦然地欺騙自己說我還小椭岩,有的是時間。直到某一天璃赡,放下...
    短耳朵兔子閱讀 942評論 2 4