昨天感冒,大晚上10点就睡了,本来今天打算休息养伤的,谁知道大下午4点的时候传来噩耗有必解bug,只能顶着伤病来到公司了。废话少说了,今天咱们来体验一下LeakCanary的内存检测功能啦。LeakCanary这个库咋用啊,调用肯定是很简单啦,在Application类里面调用一下LeakCanary.install(this);就完事了,所以说搞应用是真他妈的简单。下面五分钟计时开始!
1.下载工程,工程的github网址:https://github.com/square/leakcanary 又是square公司的,记住这个公司,这个公司太牛逼了,什么okhttp,rxjava都是这公司搞的,就没见中国有什么创造。
2.导入到Android studio中去,导入后是这个狗样
3.然后编译了,有时会报sdk不在,你就下载sdk嘛,有时还会报下面
Error:(21, 0) CreateProcess error=2, 系统找不到指定的文件。 <a href="openFile:D:\androidstdioSDK\workspace\leakcanary\leakcanary-android\build.gradle">Open File</a>
貌似是要配git的环境变量,我懒得配,直接把这句还有java中引用的地方通通删掉,就向下图
4.然后假设你编译过了,编译不过你找我。开始执行,会给你装两个apk,分别来自leakcanary-sample和leakcanary-android文件夹
安装后是这个鸟样。
然后打开左边LeakCanarySample那个apk,英文看的懂不?看不懂就别看了,这篇文章也别看了,英语都不会,还是中国人吗?英文意思,就是让你点下那个按钮,然后旋转一下屏幕。然后过个5秒,会提示了泄露了!!在状态栏可以看到,然后点一下,就会跳到上图的第二个apk去展示。
第一次运行可能通知栏提醒了给他个写存储的权限,那就给嘛。
例子程序是下面这样的,有心的人可以看下他是怎么泄露的,反正我不知道,我就是一把梳,就是干
public class MainActivity extends Activity {
@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_activity);
View button = findViewById(R.id.async_task);
button.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
startAsyncTask();
}
});
}
void startAsyncTask() {
new AsyncTask<Void, Void, Void>() {
@Override protected Void doInBackground(Void... params) {
// Do some slow work in background
SystemClock.sleep(20000);
return null;
}
}.execute();
}
}
看样子是有个匿名内部类AsyncTask造成的,匿名内部类持有外部类的引用,外部类是MainActivity ,MainActivity 调用destory的时候,AsyncTask还在干活呢,不能释放,AsyncTask不能释放,MainActivity 你就别想释放。然后现象就是MainActivity 调用destory后,MainActivity 对象还在内存死皮赖脸的活着,官方用语就是MainActivity 对象泄露了。
至于检测原理,搞应用的话,就不用知道了,调调api就用了,想这么多又不会加人工,是不是?开玩笑,简单说一下。我接单造个轮子你就知道了,十多行代码就搞定了,甚至有时我觉得你根本就不需要这个库,自己造个轮子就好。
按照我的理解,我要造这个轮子的话,是这样子造的,在activity的ondestory方法里面实现
@Override
protected void onDestroy() {
super.onDestroy();
// 开启一个后台线程,这个线程不要持有activity的应用,不然泄露又说怪这个线程
Thread detectThread=new DetectThread("detectThread");
//用一个弱引用指向这个activity,并且关联到弱引用序列,我的意思是关联。怎么关联法?这个是java的基础,你去搜下WeakReferenceQueue ,当WeakReference所指对象没有强引用时,WeakReference就是被放到这个WeakReferenceQueue 序列
ReferenceQueue queue=new ReferenceQueue();
WeakReference<Activity> weakref=new WeakReference(this,queue);
detectThread.start();//开始检查
}
在另一个文件定义DetectThread
class DetectThread extend Thread {
sleep(5000);//睡个5秒去检测
gc(); //回收下垃圾先
if(queue.contains(weakref)){
Log.i(tag,"没有泄露,做的很好");
}else{
Log.i(tag,"泄露了傻逼!!!");
}
}
基本原理太简单了,就是新建一个WeakReference对象指向要关注的Activity,Activity被回收的时候WeakReference对象会加到ReferenceQueue 队列中,检测ReferenceQueue队列 是否有WeakReference对象就知道有没有泄露了,有的话就没有泄露,没有的话就他妈泄露了。ReferenceQueue 的这一特性自己百度去,这是java基础,基础,基础!!!!!
至于真实源代码,下节我再告诉你!!其实跟我造的轮子差不多。如果我先写的话,说不定我就不开源,收费使用!!!
加班没有加班费又没有加班零食,能不能打赏我几毛钱买个烧饼?