今天是周日,早上看了腾讯课堂上的关于内存泄漏的相关视频,自己也突然来了灵感,借此记录下。
内存泄漏是Android开发中常见的问题,也是不易解决的疑难杂症,今天就抽出我遇到过的一个常用的技术点来和大家一起做一个详细的探讨。下面进入正题!!!
1,所谓的内存泄漏,其实就是内存不再GC的掌控范围之内了;当一个对象不再有任何的引用的时候才能出发GC的回收。有兴趣可以了解下GC回收的原理;
2,GC回收的原理可以这样描述下:应用程序启动,GC会为这个应用创建一个GC Root引用的根节点,根节点的下面可以是各种class对象,成树状结构;
可作为GC引用点的是:
1>JavaStack中的引用的对象;
2>方法区中静态引用指向的对象;
3>方法区中常量引用指向的对象;
4>Native方法中JNI引用的对象;
5>"Thread"--活着的线程;
3,怎么判断一个对象是垃圾对象?
这是一个主观的判断;
4,内存泄漏多了容易导致OOM--内存溢出,app会崩溃;
5,下面就以显示的实例来说明
Android开发中给我们经常会用到CommonUtil来作为Activity的工具类;
比如项目中存在Activity A,Activity B,单例模式下的CommonUtil,B中存在一个对CommUti的全局引用,A通过触发打开B实例;
当执行以下动作:A打开B,关闭B回到A,再打开B,代码如下:
public void goNext(View view) { Intent intent = new Intent(this, SecondActivity.class); startActivity(intent); }
public class CommonUtil { private static CommonUtil instance; private Context context; public CommonUtil(Context context) { this.context = context; } public static synchronized CommonUtil getIntstance(Context context) { if (instance == null) { instance = new CommonUtil(context); } return instance; } }
public class SecondActivity extends Activity { CommonUtil commonUtil; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); commonUtil = CommonUtil.getIntstance(this); } }
整个流程打开了2次Activity B;下面我们在Android Studio中打开Monitors-->Memory-->Dump Java Heap
这个时候我们会发现我们的应用堆中存在了2个SecondActivity的实例,而正常情况下,当我们关闭B的时候,B应用就销毁了,那B怎么会存在2个实例呢?
下面我们来分析下:
B中持有了一个CommonUtil的实例,CommonUti使用单例模式时传入了当前B的上下文对象,CommonUtil就持有了B的引用,而我们的CommonUtil是以static变量存在的,他会直接被上文讲到的GC Root对象引用,这样根据垃圾回收期的回收机制,当B页面关闭的时候,GC会判断B的对象是否还有没有被引用;而B的层级结构是:GC Root
-->CoomonUtil-->B,这样,GC会从B所在的层级开始一直追溯,发现中间没有断层,于是GC就认为B还在被引用的状态,也就不会被回收了;当我们下次再次打开新的B时,CommonUtil已被实例化过,所以不会重新被初始化;ComonUtil中持有的Context还会是上个B的实例对象,这个时候再次使用CommonUtil就会发生一些意想不到的错误;
6,解决方法:
在CommonUtil方法中用context.getApplicationContext() 替换context即可;