1.对于没有必要一直存在的对象,使用软引用甚至弱引用

2.少用静态变量,静态变量从类装载开始,一直到应用程序结束才回收

3.切勿在循环调用的地方去产生对象,比如很多人不会注意的在getview里new onclicklistener(),这样的方式拖动的次数越多那么就会产生越多的对象。

4.使用完对象要及时销毁,比如能局部变量的不要使用全局变量,功能用完成后要去掉对他的引用(比如置为null)

5.bitmap记得recycle,cursor要记得close

6.各种监听,广播等,注册后忘记取消等:

假设我们希望在锁屏界面(LockScreen)中,监听系统中的电话服务以获取一些信息(如信号强度等),则可以在LockScreen中定义一个PhoneStateListener的对象,同时将它注册到TelephonyManager服务中。对于LockScreen对象,当需要显示锁屏界面的时候就会创建一个LockScreen对象,而当锁屏界面消失的时候LockScreen对象就会被释放掉。
  但是如果在释放LockScreen对象的时候忘记取消我们之前注册的PhoneStateListener对象,则会导致LockScreen无法被垃圾回收。如果不断的使锁屏界面显示和消失,则最终会由于大量的LockScreen对象没有办法被回收而引起OutOfMemory,使得system_process进程挂掉。
  虽然有些系统程序,它本身好像是可以自动取消注册的(当然不及时),但是我们还是应该在我们的程序中明确的取消注册,程序结束时应该把所有的注册都取消掉。

7.Enums的内存消耗通常是static constants的2倍。你应该尽量避免在Android上使用enums

8.一般来说我们是不推荐用单例的,因为大家为了偷懒写代码更方便一个劲的整成了单例,越多的单例使用导致内存中长时间存活的对象过多,也会让内存占用过多

9.如果要使用到Context,尽量使用ApplicationContext去代替Context,因为ApplicationContext的生命周期较长,引用情况下不会造成内存泄露问题

10.集合中对象没清理造成的内存泄露

我们通常把一些对象的引用加入到了集合中,当我们不需要该对象时,并没有把它的引用从集合中清理掉,这样这个集合就会越来越大。如果这个集合是static的话,那情况就更严重了

11.资源对象和各种连接没关闭造成的内存泄露
       资源性对象,数据库连接(dataSourse.getConnection()),网络连接(socket)和io连接,除非其显式的调用了其close()方法将其连接关闭,否则是不会自动被GC 回收的,而且他们一般都使用了大得缓冲

12.Adapter要使用convertView

13.不要使用整张整张的图,尽量使用9path图片

14.不在一个Activity中使用非静态内部类, 以防它的生命周期比Activity长。相反,尽量使用持有Activity弱引用的静态内部类

15.context相关的内存泄露:

  • 静态成员变量导致的内存泄露,静态成员变量本身并不会阻止对象被回收,只要有可以到达的强引用,对象就不会回收

先看一段代码:

@Override         


          protectedvoid onCreate(Bundle state){         


                    super          .onCreate(state);         


                    


                    TextView label =          new           TextView(          this          );         


                    label.setText(          "Leaks are bad"          );         


                    


                    setContentView(label);         


          }


    大家看看有什么问题吗?

    没问题是吧,继续看:

private           static           Drawable sBackground;         


                    


          @Override         


          protected           void           onCreate(Bundle state){         


                    super          .onCreate(state);         


                    


                    TextView label =          new           TextView(          this          );         


                    label.setText(          "Leaks are bad"          );         


                    


                    if          (sBackground ==          null          ){         


                    sBackground = getDrawable(R.drawable.large_bitmap);         


                    }         


                    label.setBackgroundDrawable(sBackground);         


                    


                    setContentView(label);         


          }


    有问题吗?

    哈哈,先Hold住一下,先来说一下android各版本发布的历史:

/*         


          2.2        2010-3-20,Froyo         


          2.3        2010-12-6, Gingerbread         


          3.0        2011-2-22, Honeycomb         


          4.0        2011-10-11 Ice Cream Sandwich         


          */


    了解源码的历史,是很有益于我们分析android代码的。

    好,开始分析代码。

    首先,查看setBackgroundDrawable(Drawable background)方法源码里面有一行代码引起我们的注意:

public           void           setBackgroundDrawable(Drawable background) {         


                    // ... ...         


                    background.setCallback(          this          );         


                    // ... ...         


          }


所以sBackground对view保持了一个强引用,view对activity保持了一个强引用。

    当退出当前Activity时,当前Activity本该释放,但是因为sBackground是静态变量,它的生命周期并没有结束,而sBackground间接保持对Activity的引用,导致当前Activity对象不能被释放,进而导致内存泄露。

 所以结论是:有内存泄露!

    到此结束了吗?

    我发现网上太多直接抄或者间接抄这篇文章,一搜一大片,并且吸引了大量的Android初学者不断的转载学习。

    但是经过本人深入分析Drawable源码,事情发生了一些变化。

    Android官方文档的这篇文章是写于2009年1月的,当时的Android Source至少是Froyo之前的。

    Froyo的Drawable的setCallback()方法的实现是这样的:

public           final           void           setCallback(Callback cb) {         


                    mCallback = cb;         


          }


    在GingerBread的代码还是如此的。

    但是当进入HoneyComb,也就是3.0之后的代码我们发现Drawable的setCallback()方法的实现变成了:

public           final           void           setCallback(Callback cb) {         


                    mCallback =           new           WeakReference<Callback>(cb);         


          }


因为是弱引用,所以activity退出的时候,view的所有强引用都不可达了,sBackground中的弱引用也不会阻止view的回收,就解决了泄露的问题

也就是说3.0之后,Drawable使用了软引用,把这个泄露的例子问题修复了。

    所以最终结论是,在android3.0之前是有内存泄露,在3.0之后无内存泄露!

    如果认真比较代码的话,Android3.0前后的代码改进了大量类似代码,前面的Cursor篇里的例子也是在3.0之后修复了。

回调泄露的,同时通过官方代码的update也了解到了怎么修复类似的内存泄露。



  • 非静态内部Handler对象或非静态内部Thread对象

    先看一段代码:

public           class           MainActivity extends QActivity {         


                    // lint tip: This Handler class should be static or leaks might occur         


                    class           MyHandler extends Handler {         


                    ... ...         


                    }         


          }


    Handler泄露的关键点有两个:

    1). 内部类

    2). 生命周期和Activity不一定一致

    第一点,Handler使用的比较多,经常需要在Activity中创建内部类,所以这种场景还是很多的。

内部类持有外部类Activity的引用,当Handler对象有Message在排队(比如postdelay延时很长的时候),则无法释放,进而导致Activity对象不能释放。

    如果是声明为static,则该内部类不持有外部Acitivity的引用,则不会阻塞Activity对象的释放。

    如果声明为static后,可在其内部声明一个弱引用(WeakReference)引用外部类。

public           class           MainActivity           extends           Activity {         


                    private           CustomHandler mHandler;         


                    


                    @Override         


                    protected           void           onCreate(Bundle savedInstanceState) {         


                    super          .onCreate(savedInstanceState);         


                    mHandler =           new           CustomHandler(          this          );         


                    }         


                    


                    static           class           CustomHandlerextends Handler {         


                    // 内部声明一个弱引用,引用外部类         


                    private           WeakReference<MainActivity > activityWeakReference;         


                    public           MyHandler(MyActivity activity) {         


                    activityWeakReference=           new           WeakReference<MainActivity >(activity);         


                    }         


                    // ... ...            


                    }         


          }


    第二点,其实不单指内部类,而是所有Handler对象,如何解决上面说的Handler对象有Message在排队,而不阻塞Activity对象释放?

在Activity onStop或者onDestroy的时候,取消掉该Handler对象的Message和Runnable。

通过查看Handler的API,它有几个方法:removeCallbacks(Runnable r)和removeMessages(int what)等。

// 一切都是为了不要让mHandler拖泥带水         


          @Override         


          public           void           onDestroy() {         


                    mHandler.removeMessages(MESSAGE_1);         


                    mHandler.removeMessages(MESSAGE_2);         


                    mHandler.removeMessages(MESSAGE_3);         


                    mHandler.removeMessages(MESSAGE_4);         


                    


                    // ... ...         


                    


                    mHandler.removeCallbacks(mRunnable);         


                    


                    // ... ...         


          }


    上面的代码太长?好吧,出大招:

@Override         


          public           void           onDestroy() {         


                    //  If null, all callbacks and messages will be removed.         


                    mHandler.removeCallbacksAndMessages(          null          );         


          }


    有人会问,当Activity退出的时候,我还有好多事情要做,怎么办?我想一定有办法的,比如用Service等等.


      

线程也是造成内存泄露的一个重要的源头。线程产生内存泄露的主要原因在于线程生命周期的不可控。我们来考虑下面一段代码。


android内存性能优化 内存优化 android_内部类



1  public class MyActivity extends Activity {  
 2 
 3       @Override  
 4 
 5       public void onCreate(Bundle savedInstanceState) {  
 6 
 7          super.onCreate(savedInstanceState);  
 8 
 9          setContentView(R.layout.main);  
10 
11          new MyThread().start();  
12 
13      }  
14 
15 
16      private class MyThread extends Thread{  
17 
18          @Override  
19 
20          public void run() {  
21 
22              super.run();  
23 
24              //do somthing  
25 
26          }  
27 
28      }  
29 
30 }



android内存性能优化 内存优化 android_内部类


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

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

将线程的内部类,改为静态内部类。

在线程内部采用弱引用保存Context引用。

解决的模型如下:


android内存性能优化 内存优化 android_内部类



1 public abstract class WeakAsyncTask<Params, Progress, Result, WeakTarget> extends  
 2         AsyncTask<Params, Progress, Result> {  
 3      protected WeakReference<WeakTarget> mTarget;  
 4 
 5      public WeakAsyncTask(WeakTarget target) {  
 6         mTarget = new WeakReference<WeakTarget>(target);  
 7      }  
 8 
 9     /** {@inheritDoc} */  
10     @Override  
11      protected final void onPreExecute() {  
12          final WeakTarget target = mTarget.get();  
13          if (target != null) {  
14            this.onPreExecute(target);  
15          }  
16     }  
17 
18      /** {@inheritDoc} */  
19      @Override  
20     protected final Result doInBackground(Params... params) {  
21          final WeakTarget target = mTarget.get();  
22          if (target != null) {  
23              return this.doInBackground(target, params);  
24          } else {  
25              return null;  
26          }  
27      }  
28 
29      /** {@inheritDoc} */  
30      @Override  
31      protected final void onPostExecute(Result result) {  
32          final WeakTarget target = mTarget.get();  
33          if (target != null) {  
34              this.onPostExecute(target, result);  
35          }  
36      }  
37 
38      protected void onPreExecute(WeakTarget target) {  
39          // No default action  
40      }  
41 
42      protected abstract Result doInBackground(WeakTarget target, Params... params);  
43 
44      protected void onPostExecute(WeakTarget target, Result result) {  
45          // No default action  
46      }  
47 }