之前用eclipse的时候,咱们采用的是DDMS和MAT,不只使用步骤复杂繁琐,并且要手动排查内存泄漏的位置,操做起来比较麻烦。后来随着Android studio的潮流,我也抛弃了eclipse加入了AS。android
Android Studio也开始支持自动进行内存泄漏检查,而且操做起来也比较方便。缓存
咱们你们都知道,系统是不可能将全部的内存都分配给咱们的应用程序的。每一个程序都会有可以使用的内存上限,这被称为堆大小(Heap Size)。不一样的手机,堆大小也不尽相同,随着如今硬件设备不断提升,堆大小也提高了。若是你们想要知道本身手机的堆大小是多少,能够调用以下代码:eclipse
ActivityManager manager = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE); int heapSize = manager.getMemoryClass();
结果是以MB为单位进行返回的,咱们在开发应用程序时所使用的内存不能超出这个限制,不然就会出现OutOfMemoryError。所以,好比说咱们的程序中须要缓存一些数据,就能够根据堆大小来决定缓存数据的容量。oop
下面介绍下采用Android Studio Monitor来检测内存泄漏,栗子以下:this
每次启动MainActivity中时都会调用一个线程,而后这个线程会执行runnable的run方法 因为Runnable是一个匿名内部对象 因此握有MainActivity的引用,所以
连续启动MainActivity 4次,最后退出。按照常理来讲,MainActivity会被销毁回收,可实际可能并非这样。atom
打开Android Studio,编译代码,在模拟器或者真机上运行App,在Android Monitor下点击Monitor对应的Tab,进入以下界面spa
在Memory一栏中,能够观察不一样时间App内存的动态使用状况,点击能够手动触发GC,点击
能够进入HPROF Viewer界面,查看Java的Heap,切换到Package Tree View,方便查看,点击Analyzer Task,Android Monitor就能够为咱们自动分析泄漏的Activity,以下图线程
Reference Tree表明指向该实例的引用,能够从这里面查看内存泄漏的缘由,Shallow Size指的是该对象自己占用内存的大小,Retained Size表明该对象被释放后,垃圾回收器能回收的内存总和。code
看上图,左边是内存中的对象,右边还存在4个MainActivity实例,咱们明明是所有退出的,怎么还存在,这代表出现了内存泄露。对象
1.static变量引发的内存泄漏
由于static变量的生命周期是在类加载时开始 类卸载时结束,也就是说static变量是在程序进程死亡时才释放,若是在static变量中 引用了Activity 那么 这个Activity因为被引用,便会随static变量的生命周期同样,一直没法被释放,形成内存泄漏。
解决办法:
在Activity被静态变量引用时,使用 getApplicationContext 由于Application生命周期从程序开始到结束,和static变量的同样。
2.线程形成的内存泄漏
相似于上述例子中的状况,线程执行时间很长,及时Activity跳出还会执行,由于线程或者Runnable是Acticvity内部类,所以握有Activity的实例(由于建立内部类必须依靠外部类),所以形成Activity没法释放。
AsyncTask 有线程池,问题更严重
解决办法:
1.合理安排线程执行的时间,控制线程在Activity结束前结束。
2.将内部类改成静态内部类,并使用弱引用WeakReference来保存Activity实例 由于弱引用 只要GC发现了 就会回收它 ,所以可尽快回收
3.BitMap占用过多内存
bitmap的解析须要占用内存,可是内存只提供8M的空间给BitMap,若是图片过多,而且没有及时 recycle bitmap 那么就会形成内存溢出。
解决办法:
及时recycle 压缩图片以后加载图片
4.资源未被及时关闭形成的内存泄漏
好比一些Cursor 没有及时close 会保存有Activity的引用,致使内存泄漏
解决办法:
在onDestory方法中及时 close便可
5.Handler的使用形成的内存泄漏
因为在Handler的使用中,handler会发送message对象到 MessageQueue中 而后 Looper会轮询MessageQueue 而后取出Message执行,可是若是一个Message长时间没被取出执行,那么因为 Message中有 Handler的引用,而 Handler 通常来讲也是内部类对象,Message引用 Handler ,Handler引用 Activity 这样 使得 Activity没法回收。
解决办法:
依旧使用 静态内部类+弱引用的方式 可解决
6.带参数的单例
若是咱们在在调用Singleton的getInstance()方法时传入了Activity。那么当instance没有释放时,这个Activity会一直存在。所以形成内存泄露。
解决方法:
能够将new Singleton(context)改成new Singleton(context.getApplicationContext())便可,这样便和传入的Activity不要紧了。