android記憶體最佳化之三記憶體分析工具的使用

來源:互聯網
上載者:User

標籤:

 anroid記憶體分析工具的使用

一.Eclipse Heap分析記憶體泄露

           Android開發中避免不了碰到記憶體泄露問題,這裡先大概講下記憶體泄露的基本概念:記憶體泄露官方的解釋是是用動態儲存裝置分配函數動態開闢的空間,在使用完畢後未釋放,結果導致一直佔據該記憶體單元,直到程式結束。它也可以理解為new的新對象用完後,該對象沒有得到回收,造成的無用的對象一直佔據著記憶體,這種無用的隨著操作的次數越多,佔據的記憶體越多,直到記憶體溢出程式,報錯停止運行。記憶體溢出問題比起程式直接報錯的問題更難定位,光靠閱讀代碼來分析記憶體溢出問題工作量也有些大,所以我們就不得不藉助工具分析記憶體溢出問題。這一章節介紹的主要是如何使用記憶體分析工具MAT。我們用的最多的一般都是Eclipse內建的DDMS工具,進入DDMS後其介面如下:

 

       這裡先講下該工具的使用步驟:

 1. 通過USB線串連手機到PC上,android調試終端開啟需要進行記憶體分析的APP,點擊DDMS選項,進入堆顯示介面。

 2. 在Devices介面選擇APP的進程名,我的APP進程名是com.example.oomtest。

 3. 接著點擊如所示的左上方綠色按鈕UpdateHeap,用於更新顯示APP的記憶體堆詳情,點擊後出現右邊的Heap介面,即APP的堆的使用方式。其中Heap Size即APP的堆大小,是可變,至於上限是怎麼設定的可以看下上一章節。Allocated即當前APP分配出去的堆大小,一般進行某個操作後是否記憶體泄露可以通過查看Allocated是否增大進行簡單的判定,但是不一定準確,但是對於明顯的記憶體泄露還是可以的,比如載入大圖片並顯示時。

 4. 右邊的Heap介面,有個Cause GC按鈕是用於觸發你的手機的GC線程進行記憶體回收。這裡要提下的是一些人在監聽某個介面的堆情況時,進入某個介面退出後根本沒有點擊Cause GC,此時發現退出介面後Allocated大小增大了,以為就是記憶體泄露了。其實不是的,只是有時GC線程自己還沒掃描到你的APP,此時該APP的堆是還沒有被回收的,所以Allocated的大小比之前的增加了。所以在進行某個操作後,要查看APP的堆情況還要點擊Cause GC,建議多點擊幾次。

 5 . 步驟5的load heap按鈕是用於下載heap記憶體分析的檔案,接著要講的分析工具需要用到該檔案。

看到這裡可能有些網友會問了,有些代碼明明是記憶體泄露了,為什麼Allocted還是顯示正常的,即操作前和操作後,Allocted大小都沒變化。是的,這裡也是使用DDMS查看記憶體泄露的缺點,一些隱蔽性的記憶體泄露,用DDMS是看不出來的。所以第二節要講的是通過Memory Analyer工具進行記憶體泄露分析,這樣會準確很多,也很方便問題的定位。

二. Memory Analyer Tools的Program supect分析記憶體泄露

       先講下這個工具不是Eclipse內建的,所以需要自己下載Memory Analyer Tools(簡稱MAT,也可以作為外掛程式整合到Eclipse中),本人是自己下載Memory Analyer工具。安裝好Memory Analyer工具後,接著講操作步驟:

1.  點擊中的步驟5中的load heap按鈕下載堆分析檔案,即尾碼名為hprof的檔案。

2.  由於下載的hprof檔案在MAT中無法正常讀入,所以需要sdk中的hprof-conv進行轉換才可以在MAT正常讀入。為了方便檔案轉換,接著進入sdk中查看hprof-conv工具放在什麼位置,建議未轉換前的hprof檔案跟hprof-conv放在同一目錄下,因為接著在cmd中進行轉換時不用輸入太長的檔案路徑。本人這裡的hprof-conv工具的絕對路徑為D:\ProgramFiles\eclipse\Android-sdk-windows-full\platform-tools>hprof-conv,同時也把轉換前的hprof檔案也放到這個位置。

3.  開啟cmd,進入到hprof-conv所在的目錄下,輸入hprof-conv  old.hprof  new.hprof後按斷行符號鍵,接著在D:\ProgramFiles\eclipse\Android-sdk-windows-full\platform-tools目錄下產生的new.hprof檔案,即為MAT可以讀入的hprof檔案。註:其中old.hprof為轉換前的檔案名稱,new.hprof為轉換後的檔案名稱,

4.  開啟MAT,並匯入轉換後的hprof檔案,操作如右上方所示:

 

5.  匯入後的介面如所示,介面上的Problemsupect就是MAT幫你找出來的可能記憶體泄露的地方,看到這裡你可能會想,這樣很方便啊,MAT都幫你把所有可能記憶體泄露的地方都找出來了,接著點擊Problem Supect一個一個慢慢看就可以了,其實網上很多貼也是這麼說的。在這裡我想說通過Problem Supect來定位某些記憶體泄露問題(比如載入大圖片或者載入很多小圖片的情況下)也是一種方法,但是此方法跟Eclipse的Heap來分析記憶體泄露一樣,也是不準確的。

   

三 . MAT準確有效分析方法

        下面重點介紹下另外一種MAT分析記憶體泄露的方法。到這裡你可以又會有疑問了什麼樣的記憶體泄露是上面介紹的兩個方法可能檢測不出來的,這裡也順便說下吧。

(1). Activity的context被生命週期更長的對象(內部類和靜態變數等)佔據,導致的記憶體泄露問題。

(2). Cursor用完沒有colse造成的記憶體泄露問題。

        另外,下面的介紹會用到一些基本概念,這裡先普及下: (1)Shallow Heap是對象本身佔據的記憶體的大小,不包含其引用的對象。對於常規對象(非數組)的Shallow Size由其成員變數的數量和類型來定,而數組的ShallowSize由數群組類型和數組長度來決定,它為數組元素大小的總和。(2)Retained Heap為當前對象大小+當前對象可直接或間接引用到的對象的大小總和。(間接引用的含義:A->B->C,C就是間接引用) ,並且排除被GC Roots直接或者間接引用的對象

       操作步驟:

 

(1).步驟1,點擊Overview選項,進入到主介面

(2).步驟2,點擊Histogram選項,進入到Histogram介面,如所示。其中進程名輸入框用於輸入APP的進程名,從而可以查看APP的堆情況。

 

       下面用一個記憶體泄露例子簡單分析下,方便網友入門。在Activity中定義一個線程內部類,並線上程中長時間休眠,該測試APP的進程名為com.example.oomtest,關鍵代碼如下:

protectedvoid onCreate(BundlesavedInstanceState) {

        // TODO Auto-generated method stub

        super.onCreate(savedInstanceState);

        Log.i(TAG,"onCreate");

        setContentView(R.layout.activity_second);

        new TestThread().start();

}

publicclass TestThreadextends Thread {

        @Override

        publicvoid run() {

           super.run();

           try {

               Thread.sleep(1000 * 60 *1000);

           } catch (InterruptedExceptione) {

               e.printStackTrace();

           }

       }

 }

        進入測試介面並退出該介面操作一次,我們在擷取hropf檔案並轉換匯入MAT中,開啟Histogram介面後,在<Regex>中輸入apk的進程名字,比如本程式使用的是com.example.oomtest,接著介面會列出APP的堆情況,如所示。

 

       從中的Objects列中可以看出當退出測試介面SencondActivity時,它的執行個體存在。所以可以判定SencondActivity發生了記憶體泄露,但是使用前面介紹的兩種方法根本就分析不出APP發生了記憶體泄露。到這裡你可能也會問,知道了SencondActivity發生了記憶體泄露,那麼要怎麼知道具體哪裡發生了記憶體泄露呢?這個也簡答,這就是通過Histogram進行分析記憶體泄露的優勢了,操作步驟如所示:

 

跟著所示操作,接著出現以下介面,從中可以看出activity執行個體沒有被回收,這就是前面所說的隱藏性比較強的記憶體流失類型1了,主要原因就是Activity中的線程一直佔住了Activity的this造成的記憶體泄露,所以當該Activity被Destroy時,Activity的執行個體沒法被GC回收。

 

 

        現將線程的休眠時間修改為100時,按同樣的操作方法測試,SencondActivity的子線程由於休眠時間比較短,此時當Activity被Destroy時,Activity的this已經被釋放了,所以不會發生記憶體泄露的情況,其堆記憶體情況:

 

        從列表中可以看出此時SencondACtity的Object(對象)為0,即SencondActivity沒有存在對象,所以用該方法進行記憶體泄露分析是很準確的,但是同樣的程式通過前面的兩種方法就無法定位出哪裡出問題,甚至檢測不出記憶體泄露了。這一章就先介紹到這裡吧,下一章節將介紹其他一些隱藏性比較強的記憶體泄露問題,以便各大網友開發出高品質的APP。

 

android記憶體最佳化之三記憶體分析工具的使用

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.