成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

LeakCanary傻瓜式的內(nèi)存泄露檢測工具

shixinzhang / 2786人閱讀

摘要:另一種方式就是是一個簡單的,方便的內(nèi)存檢測工具,可以輕易的發(fā)現(xiàn)內(nèi)存問題,還會生成更加簡單清晰的報告。是一個開源的檢測內(nèi)存泄露的庫。

在開發(fā)Android應(yīng)用的過程中如果需要處理圖片或者大量數(shù)據(jù)的時候,就有可能會遇到OOMjava.lang.OutOfMemoryError),一般出現(xiàn)最多的是在創(chuàng)建Bitmap上,也有可能是在內(nèi)存中處理了大量的數(shù)據(jù)上。出現(xiàn)OOM應(yīng)用會直接崩潰,即使沒有出現(xiàn)OOM,內(nèi)存使用過大的時候應(yīng)用也會出現(xiàn)卡頓。所以內(nèi)存的優(yōu)化在開發(fā)Android應(yīng)用時是一個比較重要的任務(wù)。
一般會針對Bitamp的內(nèi)存優(yōu)化有下面幾種方式:

1. 增加進程的內(nèi)存
2. 使用Bitmap.Config.ALPHA_8(圖片失真)
3. 顯示的調(diào)用System.gc()
4. catch Exception
5. 調(diào)用bitmap.recycle()
6. 縮小bitmap的大?。ㄈ绻亲x取的原圖是一個大圖應(yīng)該先采用這種方式,Bitmap如果是剛好適配屏幕的就不需要縮小了)
7. 使用弱引用和軟引用(google已經(jīng)不建議使用了,Android的GC效率非常高,只要保證對象沒有被引用即可)

但是我們忽略掉一個問題就是什么造成了OOM
一般來說發(fā)生OOM崩潰的地方不一定是內(nèi)存泄露的地方,崩潰的原因有可能是Activity造成的內(nèi)存泄露,也可能是操作數(shù)據(jù)庫造成的內(nèi)存泄露,當(dāng)內(nèi)存已經(jīng)非常接近峰值的時候,這個時候恰巧要創(chuàng)建一個Bitmap對象就會發(fā)生OOM(Bitmap對象占用的內(nèi)存比較大)。
是什么原因造成了內(nèi)存泄露呢?

內(nèi)存泄露

我們知道Android中每個對象都有自己的生命周期,比如Activity的生命周期最后會調(diào)用onDestroy方法做銷毀處理,但如果使用Activity中調(diào)用了類似于Toast這種對象,就會把這個Activity的引用傳給了Toast,而Toast的生命周期不會隨著Activity的銷毀而銷毀,這樣就造成了Activity的內(nèi)存泄露,它會被Toast對象引用,無法被銷毀。
常見的內(nèi)存泄露形成的原因:

Toast持有Activity的引用

數(shù)據(jù)庫游標(biāo)Cursor沒有關(guān)閉

Adapter沒有復(fù)用convertView

對象被生命周期更長的對象引用,Activity被靜態(tài)集合引用

....

那如何知道應(yīng)用的內(nèi)存有沒有出現(xiàn)泄露呢?

監(jiān)控內(nèi)存的方式

Heap Dump:常見的內(nèi)存監(jiān)控方式是Heap DumpHeap Dump是一種在Java中比較常用的檢測內(nèi)存的方式:

簡單來說就是我們在一個初始狀態(tài)A, 在這個時候Dump一次內(nèi)存,在做了一些操作之后回到狀態(tài)A,再Dump一次內(nèi)存。

對兩次Dunp的內(nèi)存數(shù)據(jù)(hprof)使用分析工具做分析(MAT),根據(jù)分析的結(jié)果就能知道是否存在內(nèi)存泄露,這種方式比較復(fù)雜和繁瑣并不是特別易用。

Moitors:這是Android SDK 自帶的內(nèi)存監(jiān)控工具,Monitors能檢測到內(nèi)存的變化,比如內(nèi)存是增加還是減少。
打開一個Activity會導(dǎo)致內(nèi)存增加,關(guān)閉一個Activity會導(dǎo)致內(nèi)存減少,反復(fù)的做這樣的操作,如果每次打開一個Activity再關(guān)閉之后增加的內(nèi)存不會減少就說明這個Activity有可能有內(nèi)存泄露,再借助log輔助進行檢測,就可以發(fā)現(xiàn)內(nèi)存泄露的問題,
這種方式的缺點是并不是特別的準(zhǔn)確,因為內(nèi)存的釋放和對象的生命周期有關(guān)也和GC的調(diào)度有關(guān)。
另一種方式就是LeakCanary,LeakCanary是一個簡單的,方便的內(nèi)存檢測工具,可以輕易的發(fā)現(xiàn)內(nèi)存問題,還會生成更加簡單清晰的報告。

LeakCanary

LeakCanary是一個開源的檢測內(nèi)存泄露的java庫。項目地址:https://github.com/square/lea...
LeakCanary實際上就是在本機上自動做了Heap dump,對生成的hprof文件進行分析,展示分析的結(jié)果。和手工分析Heap Dump的方式得到的結(jié)果是一樣的。只不過這部分的工作完全自動化完成了。
下面是一個LeakCanary的結(jié)果截圖:

從上圖可以看到,LeakCanary能清晰簡單的展示出那里有內(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對應(yīng)用進行檢測它會影響程序的性能,尤其是在做Heap dump分析操作時,因此需要在依賴?yán)锩嬷付▽?yīng)的版本,debug的時候才進行分析,release的時候不能進行分析。
debugCompile可以使用檢測版本:

com.squareup.leakcanary:leakcanary-android

releaseCompile使用no-op模式,即No Operation Performed就是不會把對應(yīng)的類庫編譯,指定類庫為無用的指令:

com.squareup.leakcanary:leakcanary-android-no-op

這樣就可以指定LeakCanary為無用指令,不會在release的時候進行編譯。
Application中加入分析Activity的代碼:

public class ExampleApplication extends Application {

  @Override public void onCreate() {
    super.onCreate();
    LeakCanary.install(this);
  }
}

這樣就可以檢測所有Activity的內(nèi)存泄露了。LeakCanary內(nèi)部實現(xiàn)使用了ActivityLifecycleCallbacks方法監(jiān)聽所有Activity的生命周期。
除了Activity會發(fā)生內(nèi)存泄露以外,其他對象也有可能會出現(xiàn)內(nèi)存泄露,如果對其他對象進行檢測呢?

檢測其他對象

LeakCanary中提供了RefWatcher類,可以用來監(jiān)控所有的對象。
首先實例化RefWatcher:

public static RefWatcher sRefWatcher=LeakCanary.install(mContext);

對于監(jiān)控的對象使用:

sRefWatcher.watch(this)

一般我們是在對象銷毀的時候?qū)ο筮M行監(jiān)控,比如內(nèi)部實現(xiàn)的對于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的時候才對于activity進行監(jiān)控即可。
檢測到了內(nèi)存泄露,如果解決呢?

解決內(nèi)存泄露

一般情況內(nèi)存泄露的原因都是由于引用的使用不當(dāng)造成的,Android GC能夠保證回收循環(huán)引用(如果一個循環(huán)引用沒有外部引用時就會被回收),且Android GC效率很高,當(dāng)然GC的算法本身也在不停的改進。
一般情況下只需要盡量避免錯誤的引用方式帶來的內(nèi)存泄露問題即可:

生命周期長的對象引用生命周期短的對象,比如static的對象群引用Activity

使用Application的Context對象,而不是Activity的Context

避免非靜態(tài)類的內(nèi)部類對于類的隱式引用,使用靜態(tài)的內(nèi)部類

使用Android的緩存機制,比如ListView的復(fù)用機制

手動關(guān)閉資源,比如Curous的關(guān)閉

registerReceiver和unRegisterReceiver成對出現(xiàn)

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/65757.html

相關(guān)文章

  • 內(nèi)存泄漏優(yōu)化

    摘要:內(nèi)存泄漏會造成什么影響它是造成應(yīng)用程序的主要原因之一。靜態(tài)變量引用不當(dāng)會導(dǎo)致內(nèi)存泄漏靜態(tài)變量和會導(dǎo)致內(nèi)存泄漏,在下面這段代碼中對的和設(shè)置為靜態(tài)對象,從而產(chǎn)生內(nèi)存泄漏。 目錄介紹: 1.什么是內(nèi)存泄漏 2.內(nèi)存泄漏造成什么影響 3.內(nèi)存泄漏檢測的工具有哪些 4.關(guān)于Leakcanary使用介紹 5.Leakcanary捕捉常見的內(nèi)存泄漏及解決辦法 5.0.1 錯誤使用單例造成的內(nèi)存...

    icyfire 評論0 收藏0
  • 內(nèi)存泄漏優(yōu)化

    摘要:內(nèi)存泄漏造成什么影響它是造成應(yīng)用程序的主要原因之一。造成的內(nèi)存泄漏早時期的時候處理耗時操作多數(shù)都是采用的方式,后來逐步被取代,直到現(xiàn)在采用的方式來處理異步。 目錄介紹: 01.什么是內(nèi)存泄漏 02.內(nèi)存泄漏造成什么影響 03.內(nèi)存泄漏檢測的工具有哪些 04.關(guān)于Leakcanary使用介紹 05.錯誤使用單例造成的內(nèi)存泄漏 06.Handler使用不當(dāng)造成內(nèi)存泄漏 07.Thread...

    fanux 評論0 收藏0
  • Android內(nèi)存泄漏優(yōu)化

    摘要:內(nèi)存泄漏造成什么影響它是造成應(yīng)用程序的主要原因之一。因此總結(jié)來看,線程產(chǎn)生內(nèi)存泄露的主要原因有兩點線程生命周期的不可控。造成的內(nèi)存泄漏早時期的時候處理耗時操作多數(shù)都是采用的方式,后來逐步被取代,直到現(xiàn)在采用的方式來處理異步。 目錄介紹: 01.什么是內(nèi)存泄漏 02.內(nèi)存泄漏造成什么影響 03.內(nèi)存泄漏檢測的工具有哪些 04.關(guān)于Leakcanary使用介紹 05.錯誤使用單例造成的內(nèi)...

    sourcenode 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<