前言
java gc
为何泄漏?
泄露影响比较大的就是一些大对象,常见的比如某些资源,bitmap,以及activity。
如何发生泄漏
static
static这个关键字使一个变量变为只和这个类相关的类变量,和实例无关。他的生命周期是很长的,贯穿于app的启动到关闭。因此只要用一个static引用一个大对象,就可以泄漏了!举个例子:
static Activity activity;
这是最简单粗暴的持有一个activity的引用,这样这个activity退出之后对象并没有被销毁。
static View view;
一个View初始化时会用到context,我们在自定义View,重写构造方法时就知道这个了。因此如果一个View也像这样被持有,那个context也不会被释放。
innerClass
内部类有个特性,是他会持有一个外部类的引用。如果内部类的实例一直存活,那么外部类activity的实例也就一直在。比如持有一个static的内部类引用:
我们平时会用到很多第三方库,比如ButterKnife EventBus RxJava等等,有的时候要获取系统服务,getSystemService。在使用的时候,都有一个先registerd或者bind的操作,而且在创建的时候会把activity的引用传过去。如果在activity结束时没有unregister或者unbind,就会造成内存泄漏。
如何检测泄漏
除此之外,android studio的刀耕火种的方式也不错,在这里我拿一个例子来示范一下我是怎么用的。
首先,我写了两个activity,一个MainActivity,一个MemoryLeakActivity,逻辑是:MainActivity中有个按钮,点击会调到MemoryLeakActivity,在这个activity中会故意发生内存泄漏,代码如下:
首先这个Memory就是当前app的内存使用状况:
好了,介绍完这个工具,我们开始动手实践。首先打开app,点击按钮跳到会发生泄漏的activity上,再按返回键,然后再次按下按钮……这样反复操作:
接下来由android studio来分析一下。在反复几次上面的操作之后,返回MainActivity,然后点击dump java heap按钮,然后等一会儿,android studio在为我们dump此时的horof文件。在成功后,会自动打开:
再点击刚才results中第二个item,看一下下方的reference tree:
拓展
android studio的分析还算比较简单而且内容较少,我们可以把这个hprof导出,然后用mat来分析。
怎么解决泄漏
根据这个思路: