昨天感冒彼宠,大晚上10點就睡了,本來今天打算休息養(yǎng)傷的趣席,誰知道大下午4點的時候傳來噩耗有必解bug兵志,只能頂著傷病來到公司了。廢話少說了宣肚,今天咱們來體驗一下LeakCanary的內存檢測功能啦想罕。LeakCanary這個庫咋用啊,調用肯定是很簡單啦霉涨,在Application類里面調用一下LeakCanary.install(this);就完事了按价,所以說搞應用是真他媽的簡單。下面五分鐘計時開始笙瑟!
1.下載工程楼镐,工程的github網(wǎng)址:https://github.com/square/leakcanary 又是square公司的,記住這個公司往枷,這個公司太牛逼了框产,什么okhttp,rxjava都是這公司搞的错洁,就沒見中國有什么創(chuàng)造秉宿。
2.導入到Android studio中去,導入后是這個狗樣
3.然后編譯了屯碴,有時會報sdk不在描睦,你就下載sdk嘛,有時還會報下面
Error:(21, 0) CreateProcess error=2, 系統(tǒng)找不到指定的文件导而。 <a href="openFile:D:\androidstdioSDK\workspace\leakcanary\leakcanary-android\build.gradle">Open File</a>
貌似是要配git的環(huán)境變量忱叭,我懶得配,直接把這句還有java中引用的地方通通刪掉今艺,就向下圖
4.然后假設你編譯過了韵丑,編譯不過你找我。開始執(zhí)行虚缎,會給你裝兩個apk撵彻,分別來自leakcanary-sample和leakcanary-android文件夾
安裝后是這個鳥樣。
然后打開左邊LeakCanarySample那個apk遥巴,英文看的懂不千康?看不懂就別看了,這篇文章也別看了,英語都不會,還是中國人嗎蝇刀?英文意思际乘,就是讓你點下那個按鈕,然后旋轉一下屏幕篮昧。然后過個5秒榄笙,會提示了泄露了A巍搭盾!在狀態(tài)欄可以看到咳秉,然后點一下,就會跳到上圖的第二個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 你就別想釋放。然后現(xiàn)象就是MainActivity 調用destory后皆疹,MainActivity 對象還在內存死皮賴臉的活著疏橄,官方用語就是MainActivity 對象泄露了占拍。
至于檢測原理略就,搞應用的話,就不用知道了晃酒,調調api就用了表牢,想這么多又不會加人工,是不是贝次?開玩笑崔兴,簡單說一下。我接單造個輪子你就知道了蛔翅,十多行代碼就搞定了敲茄,甚至有時我覺得你根本就不需要這個庫,自己造個輪子就好山析。
按照我的理解堰燎,我要造這個輪子的話,是這樣子造的笋轨,在activity的ondestory方法里面實現(xiàn)
@Override
protected void onDestroy() {
super.onDestroy();
// 開啟一個后臺線程秆剪,這個線程不要持有activity的應用赊淑,不然泄露又說怪這個線程
Thread detectThread=new DetectThread("detectThread");
//用一個弱引用指向這個activity,并且關聯(lián)到弱引用序列仅讽,我的意思是關聯(lián)陶缺。怎么關聯(lián)法?這個是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,"泄露了傻逼!9拚弧黍衙!");
}
}
基本原理太簡單了荠诬,就是新建一個WeakReference對象指向要關注的Activity琅翻,Activity被回收的時候WeakReference對象會加到ReferenceQueue 隊列中,檢測ReferenceQueue隊列 是否有WeakReference對象就知道有沒有泄露了柑贞,有的話就沒有泄露方椎,沒有的話就他媽泄露了。ReferenceQueue 的這一特性自己百度去钧嘶,這是java基礎棠众,基礎,基礎S芯觥U⒛谩!J槟弧新荤!
至于真實源代碼,下節(jié)我再告訴你Lɑ恪苛骨!其實跟我造的輪子差不多。如果我先寫的話苟呐,說不定我就不開源痒芝,收費使用!GK亍严衬!
加班沒有加班費又沒有加班零食,能不能打賞我?guī)酌X買個燒餅两波?