内存空间使用完毕以后未回收, 会致使内存泄漏。有人会问:Java不是有垃圾自动回收机制么?不幸的是,在Java中仍存在不少容易致使内存泄漏的逻辑(logical leak)。虽然垃圾回收器会帮咱们干掉大部分无用的内存空间,可是对于还保持着引用,但逻辑上已经不会再用到的对象,垃圾回收器不会回收它们。java
例如android
Android内存回收管理策略图:git
图中的每一个圆节点表明对象的内存资源,箭头表明可达路径。当圆节点与 GC Roots 存在可达路径时,表示当前资源正被引用,虚拟机是没法对其进行回收的(如图中的黄色节点)。反过来,若是圆节点与 GC Roots 不存在可达路径,则意味着这块对象的内存资源再也不被程序引用,系统虚拟机能够在 GC 过程当中将其回收掉。github
从定义上讲,Android(Java)平台的内存泄漏是指没有用的对象资源任与GC-Root保持可达路径,致使系统没法进行回收。app
好比Activity的Context
,就包含大量的内存引用,一旦泄漏了Context
,也意味泄漏它指向的全部对象。异步
形成Activity泄漏的常见缘由:ide
static Activity activity; //这种代码要避免
public class Singleton { private static Singleton instance; private Context mContext; private Singleton(Context context){ this.mContext = context; } public static Singleton getInstance(Context context){ if (instance == null){ synchronized (Singleton.class){ if (instance == null){ instance = new Singleton(context); } } } return instance; } }
在调用Singleton的getInstance()方法时传入了Activity。那么当instance没有释放时,这个Activity会一直存在。所以形成内存泄露。 解决方法:函数
能够将new Singleton(context)改成new Singleton(context.getApplicationContext())便可,这样便和传入的Activity不要紧了。工具
Static Views 同理,静态的View也是不建议的gradle
Inner Classes 内部类的优点能够提升可读性和封装性,并且能够访问外部类,不幸的是,致使内存泄漏的缘由,就是内部类持有外部类实例的强引用。 例如在内部类中持有Activity对象
解决方法:
1.将内部类变成静态内部类; 2.若是有强引用Activity中的属性,则将该属性的引用方式改成弱引用; 3.在业务容许的状况下,当Activity执行onDestory时,结束这些耗时任务;
例如: 发生内存泄漏的代码:
public class LeakAct extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.aty_leak); test(); } //这儿发生泄漏 public void test() { new Thread(new Runnable() { @Override public void run() { while (true) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); } }
解决方法:
public class LeakAct extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.aty_leak); test(); } //加上static,变成静态匿名内部类 public static void test() { new Thread(new Runnable() { @Override public void run() { while (true) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); } }
1.能够把Handler类放在单独的类文件中,或者使用静态内部类即可以免泄露; 2.若是想在Handler内部去调用所在的Activity,那么能够在handler内部使用弱引用的方式去指向所在Activity.使用Static + WeakReference的方式来达到断开Handler与Activity之间存在引用关系的目的. 3.在界面销毁是,释放handler资源
@Override protected void doOnDestroy() { super.doOnDestroy(); if (mHandler != null) { mHandler.removeCallbacksAndMessages(null); } mHandler = null; mRenderCallback = null; }
线程产生内存泄露的主要缘由在于线程生命周期的不可控。若是咱们的线程是Activity的内部类,因此MyThread中保存了Activity的一个引用,当MyThread的run函数没有结束时,MyThread是不会被销毁的,所以它所引用的老的Activity也不会被销毁,所以就出现了内存泄露的问题。
Bitmap对象在不使用时,咱们应该先调用recycle()释放内存,而后才设置为null.
咱们一般把一些对象的引用加入到了集合中,当咱们不须要该对象时,并无把它的引用从集合中清理掉,这样这个集合就会愈来愈大。若是这个集合是static的话,那状况就更严重了。 解决方案:
在Activity退出以前,将集合里的东西clear,而后置为null,再退出程序。
这种Android的内存泄露比纯Java的内存泄漏还要严重,由于其余一些Android程序可能引用系统的Android程序的对象(好比注册机制)。即便Android程序已经结束了,可是别的应用程序仍然还有对Android程序的某个对象的引用,泄漏的内存依然不能被垃圾回收。 解决方案:
1.使用ApplicationContext代替ActivityContext; 2.在Activity执行onDestory时,调用反注册;
资源性对象好比(Cursor,File文件等)每每都用了一些缓冲,咱们在不使用的时候,应该及时关闭它们,以便它们的缓冲及时回收内存。而不是等待GC来处理。
由于Bitmap占用的内存实在是太多了,特别是分辨率大的图片,若是要显示多张那问题就更显著了。Android分配给Bitmap的大小只有8M. 解决方法:
BitmapFactory.Options options = new BitmapFactory.Options(); options.inSampleSize = 2;//图片宽高都为原来的二分之一,即图片为原来的四分之一
//软引用 SoftReference<Bitmap> bitmap = new SoftReference<Bitmap>(pBitmap); //回收操做 if(bitmap != null) { if(bitmap.get() != null && !bitmap.get().isRecycled()){ bitmap.get().recycle(); bitmap = null; } }
解决方案:
用新的进程起含有WebView的Activity,而且在该Activity 的onDestory() 最后加上 System.exit(0); 杀死当前进程。
Lint 是 Android Studio 自带的工具,使用姿式很简单 Analyze -> Inspect Code 而后选择想要扫面的区域便可
对可能引发泄漏的编码,Lint 都会进行舒适提示:
Square 公司出品的内存分析工具,官方地址以下:https://github.com/square/leakcanary/ LeakCanary 须要在项目代码中集成,不过代码也很是简单,以下的官方示例:
在你的 build.gradle:
dependencies { debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.6.3' releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.3' // Optional, if you use support library fragments: debugImplementation 'com.squareup.leakcanary:leakcanary-support-fragment:1.6.3' }
在 Application 类:
public class ExampleApplication extends Application { @Override public void onCreate() { super.onCreate(); if (LeakCanary.isInAnalyzerProcess(this)) { // This process is dedicated to LeakCanary for heap analysis. // You should not init your app in this process. return; } LeakCanary.install(this); // Normal app init code... } }
当内存泄漏发生时,LeakCanary 会弹窗提示并生成对应的堆存储信息记录
-3.Android Monitor
开Android Studio,编译代码,在模拟器或者真机上运行App,而后点击
,在Android Monitor下点击Monitor对应的Tab,进入以下界面
在Memory一栏中,能够观察不一样时间App内存的动态使用状况,点击
能够手动触发GC,点击
能够进入HPROF Viewer界面,查看Java的Heap,以下图
Reference Tree表明指向该实例的引用,能够从这里面查看内存泄漏的缘由,Shallow Size指的是该对象自己占用内存的大小,Retained Size表明该对象被释放后,垃圾回收器能回收的内存总和。