Android App 内存泄露之Thread

来源:互联网 发布:mp4淘宝网 编辑:程序博客网 时间:2024/05/14 07:02
出处:http://blog.csdn.net/zhuanglonghai

目录(?)[-]

  1. Thread 内存泄露
    1. 看一下下面是否存在问题
      1. 真的没有问题吗
    2. 这种线程导致的内存泄露问题应该如何解决呢
      1. 上面的两个步骤其实是切换两个对象的双向强引用链接
    3. AsynTask 内部类会如何呢

Thread 内存泄露

线程也是造成内存泄露的一个重要的源头。线程产生内存泄露的主要原因在于线程生命周期的不可控。

1.看一下下面是否存在问题

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <span style="white-space:pre">    </span>/**  
  2.  *   
  3.  * @version 1.0.0   
  4.  * @author Abay Zhuang <br/>  
  5.  *         Create at 2014-7-17  
  6.  */  
  7. public class ThreadActivity extends Activity {  
  8.     public void onCreate(Bundle savedInstanceState) {  
  9.         super.onCreate(savedInstanceState);  
  10.         setContentView(R.layout.activity_main);  
  11.         new MyThread().start();  
  12.     }  
  13.   
  14.     private class MyThread extends Thread {  
  15.         @Override  
  16.         public void run() {  
  17.             super.run();  
  18.             dosomthing();  
  19.         }  
  20.     }  
  21.     private void dosomthing(){  
  22.       
  23.     }  
  24. }  


这段代码很平常也很简单,是我们经常使用的形式。

真的没有问题吗

我们思考一个问题:假设MyThread的run函数是一个很费时的操作,当我们开启该线程后,将设备的横屏变为了竖屏,一般情况下当屏幕转换时会重新创建Activity,按照我们的想法,老的Activity应该会被销毁才对,然而事实上并非如此。由于我们的线程是Activity的内部类,所以MyThread中保存了Activity的一个引用,当MyThread的run函数没有结束时,MyThread是不会被销毁的,因此它所引用的老的Activity也不会被销毁,因此就出现了内存泄露的问题。   

2.这种线程导致的内存泄露问题应该如何解决呢?

  • 第一、将线程的内部类,改为静态内部类。
  • 第二、在线程内部采用弱引用保存Context引用。 代码如下:

    [html] view plaincopy在CODE上查看代码片派生到我的代码片
    1. <span style="white-space:pre">        </span>/**  
    2.          *   
    3.          * @version 1.0.0  
    4.          * @author Abay Zhuang <br/>  
    5.          *         Create at 2014-7-17  
    6.          */  
    7.           
    8.         public class ThreadAvoidActivity extends Activity {  
    9.             public void onCreate(Bundle savedInstanceState) {  
    10.                 super.onCreate(savedInstanceState);  
    11.                 setContentView(R.layout.activity_main);  
    12.                 new MyThread(this).start();  
    13.             }  
    14.           
    15.             private void dosomthing() {  
    16.           
    17.             }  
    18.           
    19.             private static class MyThread extends Thread {  
    20.                 WeakReference<ThreadAvoidActivity> mThreadActivityRef;  
    21.           
    22.                 public MyThread(ThreadAvoidActivity activity) {  
    23.                     mThreadActivityRef = new WeakReference<ThreadAvoidActivity>(  
    24.                             activity);  
    25.                 }  
    26.           
    27.                 @Override  
    28.                 public void run() {  
    29.                     super.run();  
    30.                     if (mThreadActivityRef == null)  
    31.                         return;  
    32.                     if (mThreadActivityRef.get() != null)  
    33.                         mThreadActivityRef.get().dosomthing();  
    34.                     // dosomthing  
    35.                 }  
    36.             }  
    37.         }  

上面的两个步骤其实是切换两个对象的双向强引用链接

  1. 静态内部类:切断Activity 对于 MyThread的强引用。
  2. 弱引用: 切断MyThread对于Activity 的强引用。

3.AsynTask 内部类会如何呢?

有些人喜欢用Android提供的AsyncTask,但事实上AsyncTask的问题更加严重,Thread只有在run函数不结束时才出现这种内存泄露问题,然而AsyncTask内部的实现机制是运用了ThreadPoolExcutor,该类产生的Thread对象的生命周期是不确定的,是应用程序无法控制的,因此如果AsyncTask作为Activity的内部类,就更容易出现内存泄露的问题。

代码如下:

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /**  
  2.  *   
  3.  * 弱引用  
  4.  * @version 1.0.0   
  5.  * @author Abay Zhuang <br/>  
  6.  *         Create at 2014-7-17  
  7.  */  
  8. public abstract class WeakAsyncTask<Params, Progress, Result, WeakTarget>  
  9.     extends AsyncTask<Params, Progress, Result> {  
  10. protected WeakReference<WeakTarget> mTarget;  
  11.   
  12. public WeakAsyncTask(WeakTarget target) {  
  13.     mTarget = new WeakReference<WeakTarget>(target);  
  14. }  
  15.   
  16. @Override  
  17. protected final void onPreExecute() {  
  18.     final WeakTarget target = mTarget.get();  
  19.     if (target != null) {  
  20.         this.onPreExecute(target);  
  21.     }  
  22. }  
  23.   
  24. @Override  
  25. protected final Result doInBackground(Params... params) {  
  26.     final WeakTarget target = mTarget.get();  
  27.     if (target != null) {  
  28.         return this.doInBackground(target, params);  
  29.     } else {  
  30.         return null;  
  31.     }  
  32. }  
  33.   
  34. @Override  
  35. protected final void onPostExecute(Result result) {  
  36.     final WeakTarget target = mTarget.get();  
  37.     if (target != null) {  
  38.         this.onPostExecute(target, result);  
  39.     }  
  40. }  
  41.   
  42. protected void onPreExecute(WeakTarget target) {  
  43.     // Nodefaultaction  
  44. }  
  45.   
  46. protected abstract Result doInBackground(WeakTarget target,  
  47.         Params... params);  
  48.   
  49. protected void onPostExecute(WeakTarget target, Result result) {  
  50.     // Nodefaultaction  
  51. }  
  52. }  

目录(?)[-]

  1. Thread 内存泄露
    1. 看一下下面是否存在问题
      1. 真的没有问题吗
    2. 这种线程导致的内存泄露问题应该如何解决呢
      1. 上面的两个步骤其实是切换两个对象的双向强引用链接
    3. AsynTask 内部类会如何呢

Thread 内存泄露

线程也是造成内存泄露的一个重要的源头。线程产生内存泄露的主要原因在于线程生命周期的不可控。

1.看一下下面是否存在问题

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <span style="white-space:pre">    </span>/**  
  2.  *   
  3.  * @version 1.0.0   
  4.  * @author Abay Zhuang <br/>  
  5.  *         Create at 2014-7-17  
  6.  */  
  7. public class ThreadActivity extends Activity {  
  8.     public void onCreate(Bundle savedInstanceState) {  
  9.         super.onCreate(savedInstanceState);  
  10.         setContentView(R.layout.activity_main);  
  11.         new MyThread().start();  
  12.     }  
  13.   
  14.     private class MyThread extends Thread {  
  15.         @Override  
  16.         public void run() {  
  17.             super.run();  
  18.             dosomthing();  
  19.         }  
  20.     }  
  21.     private void dosomthing(){  
  22.       
  23.     }  
  24. }  


这段代码很平常也很简单,是我们经常使用的形式。

真的没有问题吗

我们思考一个问题:假设MyThread的run函数是一个很费时的操作,当我们开启该线程后,将设备的横屏变为了竖屏,一般情况下当屏幕转换时会重新创建Activity,按照我们的想法,老的Activity应该会被销毁才对,然而事实上并非如此。由于我们的线程是Activity的内部类,所以MyThread中保存了Activity的一个引用,当MyThread的run函数没有结束时,MyThread是不会被销毁的,因此它所引用的老的Activity也不会被销毁,因此就出现了内存泄露的问题。   

2.这种线程导致的内存泄露问题应该如何解决呢?

  • 第一、将线程的内部类,改为静态内部类。
  • 第二、在线程内部采用弱引用保存Context引用。 代码如下:

    [html] view plaincopy在CODE上查看代码片派生到我的代码片
    1. <span style="white-space:pre">        </span>/**  
    2.          *   
    3.          * @version 1.0.0  
    4.          * @author Abay Zhuang <br/>  
    5.          *         Create at 2014-7-17  
    6.          */  
    7.           
    8.         public class ThreadAvoidActivity extends Activity {  
    9.             public void onCreate(Bundle savedInstanceState) {  
    10.                 super.onCreate(savedInstanceState);  
    11.                 setContentView(R.layout.activity_main);  
    12.                 new MyThread(this).start();  
    13.             }  
    14.           
    15.             private void dosomthing() {  
    16.           
    17.             }  
    18.           
    19.             private static class MyThread extends Thread {  
    20.                 WeakReference<ThreadAvoidActivity> mThreadActivityRef;  
    21.           
    22.                 public MyThread(ThreadAvoidActivity activity) {  
    23.                     mThreadActivityRef = new WeakReference<ThreadAvoidActivity>(  
    24.                             activity);  
    25.                 }  
    26.           
    27.                 @Override  
    28.                 public void run() {  
    29.                     super.run();  
    30.                     if (mThreadActivityRef == null)  
    31.                         return;  
    32.                     if (mThreadActivityRef.get() != null)  
    33.                         mThreadActivityRef.get().dosomthing();  
    34.                     // dosomthing  
    35.                 }  
    36.             }  
    37.         }  

上面的两个步骤其实是切换两个对象的双向强引用链接

  1. 静态内部类:切断Activity 对于 MyThread的强引用。
  2. 弱引用: 切断MyThread对于Activity 的强引用。

3.AsynTask 内部类会如何呢?

有些人喜欢用Android提供的AsyncTask,但事实上AsyncTask的问题更加严重,Thread只有在run函数不结束时才出现这种内存泄露问题,然而AsyncTask内部的实现机制是运用了ThreadPoolExcutor,该类产生的Thread对象的生命周期是不确定的,是应用程序无法控制的,因此如果AsyncTask作为Activity的内部类,就更容易出现内存泄露的问题。

代码如下:

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /**  
  2.  *   
  3.  * 弱引用  
  4.  * @version 1.0.0   
  5.  * @author Abay Zhuang <br/>  
  6.  *         Create at 2014-7-17  
  7.  */  
  8. public abstract class WeakAsyncTask<Params, Progress, Result, WeakTarget>  
  9.     extends AsyncTask<Params, Progress, Result> {  
  10. protected WeakReference<WeakTarget> mTarget;  
  11.   
  12. public WeakAsyncTask(WeakTarget target) {  
  13.     mTarget = new WeakReference<WeakTarget>(target);  
  14. }  
  15.   
  16. @Override  
  17. protected final void onPreExecute() {  
  18.     final WeakTarget target = mTarget.get();  
  19.     if (target != null) {  
  20.         this.onPreExecute(target);  
  21.     }  
  22. }  
  23.   
  24. @Override  
  25. protected final Result doInBackground(Params... params) {  
  26.     final WeakTarget target = mTarget.get();  
  27.     if (target != null) {  
  28.         return this.doInBackground(target, params);  
  29.     } else {  
  30.         return null;  
  31.     }  
  32. }  
  33.   
  34. @Override  
  35. protected final void onPostExecute(Result result) {  
  36.     final WeakTarget target = mTarget.get();  
  37.     if (target != null) {  
  38.         this.onPostExecute(target, result);  
  39.     }  
  40. }  
  41.   
  42. protected void onPreExecute(WeakTarget target) {  
  43.     // Nodefaultaction  
  44. }  
  45.   
  46. protected abstract Result doInBackground(WeakTarget target,  
  47.         Params... params);  
  48.   
  49. protected void onPostExecute(WeakTarget target, Result result) {  
  50.     // Nodefaultaction  
  51. }  
  52. }  
0 0
原创粉丝点击