Android內存泄露之Thread

kysh1925 8年前發布 | 7K 次閱讀 Android開發 移動開發

 線程也是造成內存泄露的一個重要的源頭。線程產生內存泄露的主要原因在于線程生命周期的不可控。 

1.看一下下面是否存在問題

/*
    

* @version 1.0.0
* @author Abay Zhuang <br/>
*         Create at 2014-7-17
*/

public class ThreadActivity extends Activity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); new MyThread().start(); }

   private class MyThread extends Thread {
       @Override
       public void run() {
           super.run();
           dosomthing();
       }
   }
   private void dosomthing(){

   }

}</pre>


這段代碼很平常也很簡單,是我們經常使用的形式。

真的沒有問題嗎

我們思考一個問題:假設MyThreadrun函數是一個很費時的操作,當我們開啟該線程后,將設備的橫屏變為了豎屏,一般情況下當屏幕轉換時會重新創建Activity,按照我們的想法,老的Activity應該會被銷毀才對,然而事實上并非如此。由于我們的線程是Activity的內部類,所以MyThread中保存了Activity的一個引用,當MyThreadrun函數沒有結束時,MyThread是不會被銷毀的,因此它所引用的老的Activity也不會被銷毀,因此就出現了內存泄露的問題。

2.這種線程導致的內存泄露問題應該如何解決呢?

  • 第一、將線程的內部類,改為靜態內部類。

  • 第二、在線程內部采用弱引用保存Context引用。 代碼如下:

/*
 

  • @version 1.0.0
  • @author Abay Zhuang <br/>
  • Create at 2014-7-17 */ public class ThreadAvoidActivity extends Activity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); new MyThread(this).start(); } private void dosomthing() { } private static class MyThread extends Thread { WeakReference<ThreadAvoidActivity> mThreadActivityRef; public MyThread(ThreadAvoidActivity activity) { mThreadActivityRef = new WeakReference<ThreadAvoidActivity>(
         activity);
    
    } @Override public void run() { super.run(); if (mThreadActivityRef == null)
     return;
    
    if (mThreadActivityRef.get() != null)
     mThreadActivityRef.get().dosomthing();
    
    // dosomthing } } }</pre>

    上面的兩個步驟其實是切換兩個對象的雙向強引用鏈接

    1. 靜態內部類:切斷Activity 對于 MyThread的強引用。

    2. 弱引用: 切斷MyThread對于Activity 的強引用。

    3.AsynTask 內部類會如何呢?

    有些人喜歡用Android提供的AsyncTask,但事實上AsyncTask的問題更加嚴重, Thread只有在run函數不結束時才出現這種內存泄露問題,然而AsyncTask內部的實現機制是運用了ThreadPoolExcutor, 該類產生的Thread對象的生命周期是不確定的,是應用程序無法控制的, 因此如果AsyncTask作為Activity的內部類,就更容易出現內存泄露的問題。

    代碼如下:

    /*
  • 弱引用
  • @version 1.0.0
  • @author Abay Zhuang <br/>
  • Create at 2014-7-17 */ public abstract class WeakAsyncTask<Params, Progress, Result, WeakTarget> extends AsyncTask<Params, Progress, Result> { protected WeakReference<WeakTarget> mTarget; public WeakAsyncTask(WeakTarget target) { mTarget = new WeakReference<WeakTarget>(target); } @Override protected final void onPreExecute() { final WeakTarget target = mTarget.get(); if (target != null) { this.onPreExecute(target); } } @Override protected final Result doInBackground(Params... params) { final WeakTarget target = mTarget.get(); if (target != null) { return this.doInBackground(target, params); } else { return null; } } @Override protected final void onPostExecute(Result result) { final WeakTarget target = mTarget.get(); if (target != null) { this.onPostExecute(target, result); } } protected void onPreExecute(WeakTarget target) { // Nodefaultaction } protected abstract Result doInBackground(WeakTarget target, Params... params); protected void onPostExecute(WeakTarget target, Result result) { // Nodefaultaction } }</pre>

     

 本文由用戶 kysh1925 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!