Android App 記憶體泄露之Thread
Thread 記憶體泄露
線程也是造成記憶體泄露的一個重要的源頭。線程產生記憶體泄露的主要原因在於線程生命週期的不可控。
1.看一下下面是否存在問題
/** * * @version 1.0.0 * @author Abay Zhuang
* 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 {@Overridepublic void run() {super.run();dosomthing();}}private void dosomthing(){}}
這段代碼很平常也很簡單,是我們經常使用的形式。
真的沒有問題嗎
我們思考一個問題:假設MyThread的run函數是一個很費時的操作,當我們開啟該線程後,將裝置的橫屏變為了豎屏,一般情況下當螢幕轉換時會重新建立Activity,按照我們的想法,老的Activity應該會被銷毀才對,然而事實上並非如此。由於我們的線程是Activity的內部類,所以MyThread中儲存了Activity的一個引用,當MyThread的run函數沒有結束時,MyThread是不會被銷毀的,因此它所引用的老的Activity也不會被銷毀,因此就出現了記憶體泄露的問題。
2.這種線程導致的記憶體泄露問題應該如何解決呢?
- 第一、將線程的內部類,改為靜態內部類。
第二、線上程內部採用弱引用儲存Context引用。 代碼如下:
/** * * @version 1.0.0 * @author Abay Zhuang
* 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 mThreadActivityRef;public MyThread(ThreadAvoidActivity activity) {mThreadActivityRef = new WeakReference(activity);}@Overridepublic void run() {super.run();if (mThreadActivityRef == null)return;if (mThreadActivityRef.get() != null)mThreadActivityRef.get().dosomthing();// dosomthing}}}
上面的兩個步驟其實是切換兩個對象的雙向強引用連結
- 靜態內部類:切斷Activity 對於 MyThread的強引用。
- 弱引用: 切斷MyThread對於Activity 的強引用。3.AsynTask 內部類會如何呢?
有些人喜歡用Android提供的AsyncTask,但事實上AsyncTask的問題更加嚴重,Thread只有在run函數不結束時才出現這種記憶體泄露問題,然而AsyncTask內部的實現機制是運用了ThreadPoolExcutor,該類產生的Thread對象的生命週期是不確定的,是應用程式無法控制的,因此如果AsyncTask作為Activity的內部類,就更容易出現記憶體泄露的問題。
代碼如下:
/** * * 弱引用 * @version 1.0.0 * @author Abay Zhuang
* Create at 2014-7-17 */public abstract class WeakAsyncTask extends AsyncTask {protected WeakReference mTarget;public WeakAsyncTask(WeakTarget target) { mTarget = new WeakReference(target);}@Overrideprotected final void onPreExecute() { final WeakTarget target = mTarget.get(); if (target != null) { this.onPreExecute(target); }}@Overrideprotected final Result doInBackground(Params... params) { final WeakTarget target = mTarget.get(); if (target != null) { return this.doInBackground(target, params); } else { return null; }}@Overrideprotected 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}}