1.GC root:
1、 Class:由系统的类加载器加载的类对象 2、 Static Fields 3、 Thread:活着的线程 4、 Stack Local: java方法的局部变量或参数 5、 JNI Local: JNI方法中的局部引用 6、 JNI Global: 全局的JNI引用 7、 Monitor used: 用于同步的监控对象 8、Help by VM: 用于JVM特殊目的由GC保留的对象 |
每个应用最大可使用的堆内存受到Android系统的限制:getMemoryClass()
2.context内存泄露
1、如果一个类持有Context对象的强引用,就需要检查其生存周期是否比Context对象更长。否则就可能发生Context泄漏。 2、View持有其创建所在Context对象的引用,如果将View对象传递给其它生存周期比View所在Context更长的强引用,就可能会引起内存泄漏。 例如View#setTag(int, Object)的内存泄漏https://code.google.com/p/android/issues/detail?id=18273 3、把Context对象赋给static变量。 |
避免Context对象泄漏Checklist 1、检查所有持有对Context对象强引用的对象的生命周期是否超出其所持有的Context对象的生命周期。 2、检查有没有把View传出到View所在Context之外的地方,如果有的话就需要检查生命周期。 3、工具类中最好不要有Context成员变量,尽量在调用函数时直接通过调用参数传入。如果必须有Context成员变量时,可以考虑使用WeakReference来引用Context对象。 4、View持有其创建所在Context对象的引用,如果将View对象传递给其它生存周期比View所在Context更长的强引用,就可能会引起内存泄漏。 5、 检查把Context或者View对象赋给static变量的地方,看是否有Context泄漏。 6、检查所有把View放入容器类的地方(特别是static容器类),看是否有内存泄漏。7、使用WeakHashMap也需要注意有没有value-key的引用。 7、尽量使用ApplicationContext。 |
3.handler泄露
发送到Handler的Message实际上是加入到了主线程的消息队列等待处理,每一个Message持有其目标Handler的强引用。
如我们通常使用的匿名内部类Handler
Handler mHandler = new Handler() { @Override public voidhandleMessage(Message msg) { mImageView.setImageBitmap(mBitmap); } }
上面是一段简单的Handler的使用。当使用内部类(包括匿名类)来创建Handler的时候,Handler对象会隐式地持有一个外部类对象(通常是一个Activity)的引用,因为View会依附着一个Activity。而Handler通常会伴随着一个耗时的后台线程(例如从网络拉取图片)一起出现,这个后台线程在任务执行完毕(例如图片下载完毕)之后,通过消息机制通知Handler,然后Handler把图片更新到界面。然而,如果用户在网络请求过程中关闭了Activity,正常情况下,Activity不再被使用,它就有可能在GC检查时被回收掉,但由于这时线程尚未执行完,而该线程持有Handler的引用(不然它怎么发消息给Handler?),这个Handler又持有Activity的引用,就导致该Activity无法被回收(即内存泄露),直到网络请求结束(例如图片下载完毕)。另外,如果你执行了Handler的postDelayed()方法,该方法会将你的Handler装入一个Message,并把这条Message推到MessageQueue中,那么在你设定的delay到达之前,会有一条MessageQueue -> Message -> Handler -> Activity的链,导致你的Activity被持有引用而无法被回收。
当然,应为是Handler对外部持有引用的原因,我们就可以将Activity设置为一个弱引用,在不必要的时候,不再执行内部方法。
publicclass WeakRefHandler extends Handler { WeakReference<Context> mWeakContext; public WeakRefHandler(Context context) { mWeakContext = newWeakReference<Context>(context); } @Override public void handleMessage(Message msg) { if((mWeakContext.get() instanceofActivity )&& ((Activity)mWeakContext.get()).isFinishing()) return ; if(mWeakContext==null){ return ; } super.handleMessage(msg); } }