摘要:另一種方式就是是一個(gè)簡(jiǎn)單的,方便的內(nèi)存檢測(cè)工具,可以輕易的發(fā)現(xiàn)內(nèi)存問題,還會(huì)生成更加簡(jiǎn)單清晰的報(bào)告。是一個(gè)開源的檢測(cè)內(nèi)存泄露的庫。
在開發(fā)Android應(yīng)用的過程中如果需要處理圖片或者大量數(shù)據(jù)的時(shí)候,就有可能會(huì)遇到OOM(java.lang.OutOfMemoryError),一般出現(xiàn)最多的是在創(chuàng)建Bitmap上,也有可能是在內(nèi)存中處理了大量的數(shù)據(jù)上。出現(xiàn)OOM應(yīng)用會(huì)直接崩潰,即使沒有出現(xiàn)OOM,內(nèi)存使用過大的時(shí)候應(yīng)用也會(huì)出現(xiàn)卡頓。所以內(nèi)存的優(yōu)化在開發(fā)Android應(yīng)用時(shí)是一個(gè)比較重要的任務(wù)。
一般會(huì)針對(duì)Bitamp的內(nèi)存優(yōu)化有下面幾種方式:
1. 增加進(jìn)程的內(nèi)存 2. 使用Bitmap.Config.ALPHA_8(圖片失真) 3. 顯示的調(diào)用System.gc() 4. catch Exception 5. 調(diào)用bitmap.recycle() 6. 縮小bitmap的大小(如果是讀取的原圖是一個(gè)大圖應(yīng)該先采用這種方式,Bitmap如果是剛好適配屏幕的就不需要縮小了) 7. 使用弱引用和軟引用(google已經(jīng)不建議使用了,Android的GC效率非常高,只要保證對(duì)象沒有被引用即可)
但是我們忽略掉一個(gè)問題就是什么造成了OOM?
一般來說發(fā)生OOM崩潰的地方不一定是內(nèi)存泄露的地方,崩潰的原因有可能是Activity造成的內(nèi)存泄露,也可能是操作數(shù)據(jù)庫造成的內(nèi)存泄露,當(dāng)內(nèi)存已經(jīng)非常接近峰值的時(shí)候,這個(gè)時(shí)候恰巧要?jiǎng)?chuàng)建一個(gè)Bitmap對(duì)象就會(huì)發(fā)生OOM(Bitmap對(duì)象占用的內(nèi)存比較大)。
是什么原因造成了內(nèi)存泄露呢?
我們知道Android中每個(gè)對(duì)象都有自己的生命周期,比如Activity的生命周期最后會(huì)調(diào)用onDestroy方法做銷毀處理,但如果使用Activity中調(diào)用了類似于Toast這種對(duì)象,就會(huì)把這個(gè)Activity的引用傳給了Toast,而Toast的生命周期不會(huì)隨著Activity的銷毀而銷毀,這樣就造成了Activity的內(nèi)存泄露,它會(huì)被Toast對(duì)象引用,無法被銷毀。
常見的內(nèi)存泄露形成的原因:
Toast持有Activity的引用
數(shù)據(jù)庫游標(biāo)Cursor沒有關(guān)閉
Adapter沒有復(fù)用convertView
對(duì)象被生命周期更長(zhǎng)的對(duì)象引用,Activity被靜態(tài)集合引用
....
那如何知道應(yīng)用的內(nèi)存有沒有出現(xiàn)泄露呢?
監(jiān)控內(nèi)存的方式Heap Dump:常見的內(nèi)存監(jiān)控方式是Heap Dump,Heap Dump是一種在Java中比較常用的檢測(cè)內(nèi)存的方式:
簡(jiǎn)單來說就是我們?cè)谝粋€(gè)初始狀態(tài)A, 在這個(gè)時(shí)候Dump一次內(nèi)存,在做了一些操作之后回到狀態(tài)A,再Dump一次內(nèi)存。
對(duì)兩次Dunp的內(nèi)存數(shù)據(jù)(hprof)使用分析工具做分析(MAT),根據(jù)分析的結(jié)果就能知道是否存在內(nèi)存泄露,這種方式比較復(fù)雜和繁瑣并不是特別易用。
Moitors:這是Android SDK 自帶的內(nèi)存監(jiān)控工具,Monitors能檢測(cè)到內(nèi)存的變化,比如內(nèi)存是增加還是減少。
打開一個(gè)Activity會(huì)導(dǎo)致內(nèi)存增加,關(guān)閉一個(gè)Activity會(huì)導(dǎo)致內(nèi)存減少,反復(fù)的做這樣的操作,如果每次打開一個(gè)Activity再關(guān)閉之后增加的內(nèi)存不會(huì)減少就說明這個(gè)Activity有可能有內(nèi)存泄露,再借助log輔助進(jìn)行檢測(cè),就可以發(fā)現(xiàn)內(nèi)存泄露的問題,
這種方式的缺點(diǎn)是并不是特別的準(zhǔn)確,因?yàn)閮?nèi)存的釋放和對(duì)象的生命周期有關(guān)也和GC的調(diào)度有關(guān)。
另一種方式就是LeakCanary,LeakCanary是一個(gè)簡(jiǎn)單的,方便的內(nèi)存檢測(cè)工具,可以輕易的發(fā)現(xiàn)內(nèi)存問題,還會(huì)生成更加簡(jiǎn)單清晰的報(bào)告。
LeakCanary是一個(gè)開源的檢測(cè)內(nèi)存泄露的java庫。項(xiàng)目地址:https://github.com/square/lea...
LeakCanary實(shí)際上就是在本機(jī)上自動(dòng)做了Heap dump,對(duì)生成的hprof文件進(jìn)行分析,展示分析的結(jié)果。和手工分析Heap Dump的方式得到的結(jié)果是一樣的。只不過這部分的工作完全自動(dòng)化完成了。
下面是一個(gè)LeakCanary的結(jié)果截圖:
從上圖可以看到,LeakCanary能清晰簡(jiǎn)單的展示出那里有內(nèi)存泄露的問題。那LeakCanary如何使用呢?
集成LeakCanary在build.gradle添加依賴:
dependencies { debugCompile "com.squareup.leakcanary:leakcanary-android:1.3.1" releaseCompile "com.squareup.leakcanary:leakcanary-android-no-op:1.3.1" testCompile "com.squareup.leakcanary:leakcanary-android-no-op:1.3.1" }
使用LeakCanary對(duì)應(yīng)用進(jìn)行檢測(cè)它會(huì)影響程序的性能,尤其是在做Heap dump和分析操作時(shí),因此需要在依賴?yán)锩嬷付▽?duì)應(yīng)的版本,debug的時(shí)候才進(jìn)行分析,release的時(shí)候不能進(jìn)行分析。
debugCompile可以使用檢測(cè)版本:
com.squareup.leakcanary:leakcanary-android
releaseCompile使用no-op模式,即No Operation Performed就是不會(huì)把對(duì)應(yīng)的類庫編譯,指定類庫為無用的指令:
com.squareup.leakcanary:leakcanary-android-no-op
這樣就可以指定LeakCanary為無用指令,不會(huì)在release的時(shí)候進(jìn)行編譯。
在Application中加入分析Activity的代碼:
public class ExampleApplication extends Application { @Override public void onCreate() { super.onCreate(); LeakCanary.install(this); } }
這樣就可以檢測(cè)所有Activity的內(nèi)存泄露了。LeakCanary內(nèi)部實(shí)現(xiàn)使用了ActivityLifecycleCallbacks方法監(jiān)聽所有Activity的生命周期。
除了Activity會(huì)發(fā)生內(nèi)存泄露以外,其他對(duì)象也有可能會(huì)出現(xiàn)內(nèi)存泄露,如果對(duì)其他對(duì)象進(jìn)行檢測(cè)呢?
LeakCanary中提供了RefWatcher類,可以用來監(jiān)控所有的對(duì)象。
首先實(shí)例化RefWatcher:
public static RefWatcher sRefWatcher=LeakCanary.install(mContext);
對(duì)于監(jiān)控的對(duì)象使用:
sRefWatcher.watch(this)
一般我們是在對(duì)象銷毀的時(shí)候?qū)?duì)象進(jìn)行監(jiān)控,比如內(nèi)部實(shí)現(xiàn)的對(duì)于Activity的監(jiān)控的原理如下:
private final ActivityLifecycleCallbacks lifecycleCallbacks = new ActivityLifecycleCallbacks() { public void onActivityCreated(Activity activity, Bundle savedInstanceState) { } public void onActivityStarted(Activity activity) { } public void onActivityResumed(Activity activity) { } public void onActivityPaused(Activity activity) { } public void onActivityStopped(Activity activity) { } public void onActivitySaveInstanceState(Activity activity, Bundle outState) { } public void onActivityDestroyed(Activity activity) { ActivityRefWatcher.this.onActivityDestroyed(activity); } };
只是在onActivityDestroyed的時(shí)候才對(duì)于activity進(jìn)行監(jiān)控即可。
檢測(cè)到了內(nèi)存泄露,如果解決呢?
一般情況內(nèi)存泄露的原因都是由于引用的使用不當(dāng)造成的,Android GC能夠保證回收循環(huán)引用(如果一個(gè)循環(huán)引用沒有外部引用時(shí)就會(huì)被回收),且Android GC效率很高,當(dāng)然GC的算法本身也在不停的改進(jìn)。
一般情況下只需要盡量避免錯(cuò)誤的引用方式帶來的內(nèi)存泄露問題即可:
生命周期長(zhǎng)的對(duì)象引用生命周期短的對(duì)象,比如static的對(duì)象群引用Activity
使用Application的Context對(duì)象,而不是Activity的Context
避免非靜態(tài)類的內(nèi)部類對(duì)于類的隱式引用,使用靜態(tài)的內(nèi)部類
使用Android的緩存機(jī)制,比如ListView的復(fù)用機(jī)制
手動(dòng)關(guān)閉資源,比如Curous的關(guān)閉
registerReceiver和unRegisterReceiver成對(duì)出現(xiàn)
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/65757.html
摘要:內(nèi)存泄漏會(huì)造成什么影響它是造成應(yīng)用程序的主要原因之一。靜態(tài)變量引用不當(dāng)會(huì)導(dǎo)致內(nèi)存泄漏靜態(tài)變量和會(huì)導(dǎo)致內(nèi)存泄漏,在下面這段代碼中對(duì)的和設(shè)置為靜態(tài)對(duì)象,從而產(chǎn)生內(nèi)存泄漏。 目錄介紹: 1.什么是內(nèi)存泄漏 2.內(nèi)存泄漏造成什么影響 3.內(nèi)存泄漏檢測(cè)的工具有哪些 4.關(guān)于Leakcanary使用介紹 5.Leakcanary捕捉常見的內(nèi)存泄漏及解決辦法 5.0.1 錯(cuò)誤使用單例造成的內(nèi)存...
摘要:內(nèi)存泄漏造成什么影響它是造成應(yīng)用程序的主要原因之一。造成的內(nèi)存泄漏早時(shí)期的時(shí)候處理耗時(shí)操作多數(shù)都是采用的方式,后來逐步被取代,直到現(xiàn)在采用的方式來處理異步。 目錄介紹: 01.什么是內(nèi)存泄漏 02.內(nèi)存泄漏造成什么影響 03.內(nèi)存泄漏檢測(cè)的工具有哪些 04.關(guān)于Leakcanary使用介紹 05.錯(cuò)誤使用單例造成的內(nèi)存泄漏 06.Handler使用不當(dāng)造成內(nèi)存泄漏 07.Thread...
摘要:內(nèi)存泄漏造成什么影響它是造成應(yīng)用程序的主要原因之一。因此總結(jié)來看,線程產(chǎn)生內(nèi)存泄露的主要原因有兩點(diǎn)線程生命周期的不可控。造成的內(nèi)存泄漏早時(shí)期的時(shí)候處理耗時(shí)操作多數(shù)都是采用的方式,后來逐步被取代,直到現(xiàn)在采用的方式來處理異步。 目錄介紹: 01.什么是內(nèi)存泄漏 02.內(nèi)存泄漏造成什么影響 03.內(nèi)存泄漏檢測(cè)的工具有哪些 04.關(guān)于Leakcanary使用介紹 05.錯(cuò)誤使用單例造成的內(nèi)...
閱讀 961·2021-11-24 09:39
閱讀 3383·2021-10-27 14:20
閱讀 2322·2019-08-30 14:08
閱讀 3361·2019-08-29 16:34
閱讀 2176·2019-08-26 12:14
閱讀 2104·2019-08-26 11:54
閱讀 2771·2019-08-26 11:44
閱讀 2474·2019-08-26 11:38