zoukankan      html  css  js  c++  java
  • Android App 内存泄露之Thread

    Thread 内存泄露

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

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

     <span style="white-space:pre">	</span>/**
    	 * 
    	 * @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(){
    		
    		}
    	}



    
    这段代码非常寻常也非常easy,是我们常常使用的形式。

    
    

    真的没有问题吗

    我们思考一个问题:如果MyThread的run函数是一个非常费时的操作,当我们开启该线程后,将设备的横屏变为了竖屏。
    普通情况下当屏幕转换时会又一次创建Activity,依照我们的想法。老的Activity应该会被销毁才对,然而其实并不是如此。

    因为我们的线程是Activity的内部类。所以MyThread中保存了Activity的一个引用,当MyThread的run函数没有结束时, MyThread是不会被销毁的。因此它所引用的老的Activity也不会被销毁。因此就出现了内存泄露的问题。

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

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

      <span style="white-space:pre">		</span>/**
      		 * 
      		 * @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
      				}
      			}
      		}


      
      
      
      

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

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

    3.AsynTask 内部类会怎样呢?

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

    代码例如以下:

    /**
     * 
     * 弱引用
     * @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
    }
    }


  • 相关阅读:
    HDU 1728 逃离迷宫
    程序猿求职之道(《程序猿面试笔试宝典》)之不想签约,但也不想轻易放弃机会,怎么办?
    职场生涯(—)
    Python学习笔记24:Django搭建简单的博客站点(二)
    &quot;高可用方案工具包&quot; high availability toolkit 1.1
    [Swift]LeetCode421. 数组中两个数的最大异或值 | Maximum XOR of Two Numbers in an Array
    [Swift]LeetCode420. 强密码检验器 | Strong Password Checker
    [Swift]LeetCode419. 甲板上的战舰 | Battleships in a Board
    [Swift]LeetCode417. 太平洋大西洋水流问题 | Pacific Atlantic Water Flow
    [Swift通天遁地]七、数据与安全-(11)如何检测应用程序中的内存泄露
  • 原文地址:https://www.cnblogs.com/slgkaifa/p/7083222.html
Copyright © 2011-2022 走看看