如何檢查 Android 應用的記憶體使用量情況,檢查android

來源:互聯網
上載者:User

如何檢查 Android 應用的記憶體使用量情況,檢查android

Android是為行動裝置而設計的,所以應該關注應用的記憶體使用量情況。儘管Android的Dalvik虛擬機器會定期執行記憶體回收操作,但這也不意味著就可以忽視應用在何時何處進行記憶體配置和釋放。為了提供良好的使用者體驗,做到系統在不同應用間流暢切換,當使用者和應用無互動時,避免應用不必要的記憶體消耗是很重要的。

儘管在開發過程中很好的遵守了《管理應用記憶體》(Managing Your App Memory )中的原則(也是應該遵守的),仍然可能會有對象泄露或引入其他的記憶體bug。對此的安全性,可以採取的措施就是Android代碼加密,本機資料保護等一系列安全的加密技術。想詳細瞭解的可以關注下愛加密,專業的行動裝置 App安全智慧型服務供應商!唯一來確定應用使用了儘可能少的記憶體的方法,就是使用工具來分析應用的記憶體使用量情況。

解析日誌資訊

最簡單的調查應用記憶體使用量情況的地方就是Dalvik日誌資訊。可以在logcat(輸出資訊可以在Device Monitor或者IDE中查看到,例如Eclipse和Android Studio)中找到這些日誌資訊。每次有記憶體回收發生,logcat會列印出帶有下面資訊的日誌訊息:

D/dalvikvm: <GC_Reason> <Amount_freed>, <Heap_stats>, <External_memory_stats>, <Pause_time>

GC原因

觸發記憶體回收執行的原因和記憶體回收的類型。原因主要包括:

GC_CONCURRENT

並發記憶體回收,當堆開始填滿時觸發來釋放記憶體。

GC_FOR_MALLOC

堆已經滿了時應用再去嘗試分配記憶體觸發的記憶體回收,這時系統必須暫停應用運行來回收記憶體。

GC_HPROF_DUMP_HEAP

建立HPROF檔案來分析應用時觸發的記憶體回收。

GC_EXPLICIT

顯式記憶體回收,例如當調用 gc()(應該避免手動調用而是要讓記憶體回收行程在需要時主動調用)時會觸發。

GC_EXTERNAL_ALLOC

這種只會在API 10和更低的版本(新版本記憶體都只在Dalvik堆中分配)中會有。回收外部分配的記憶體(例如儲存在本地記憶體或NIO位元組緩衝區的像素資料)。

釋放數量

執行記憶體回收後記憶體釋放的數量。

堆狀態

閒置百分比和(使用中的物件的數量)/(總的堆大小)。

外部記憶體狀態

API 10和更低版本中的外部分配的記憶體(分配的記憶體大小)/(回收發生時的限制值)。

暫停時間

越大的堆的暫停時間就越長。並發回收暫停時間分為兩部分:一部分在回收開始時,另一部分在回收將近結束時。

例如:

D/dalvikvm( 9050): GC_CONCURRENT freed 2049K, 65% free 3571K/9991K, external 4703K/5261K, paused 2ms+2ms

隨著這些日誌訊息的增多,注意堆狀態(上面例子中的3571K/9991K)的變化。如果值一直增大並且不會減小下來,那麼就可能有記憶體泄露了。

查看堆的更新

為了得到應用記憶體的使用類型和時間,可以在Device Monitor中即時查看應用堆的更新:

1.開啟Device Monitor。

從<sdk>/tools/路徑下載入monitor工具。

2.在Debug Monitor視窗,從左邊的進程列表中選擇要查看的應用進程。

3.點擊進程列表上面的Update Heap。

4.在右側面板中選擇Heap標籤頁。

 

Heap視圖顯示了堆記憶體使用量的基本狀況,每次記憶體回收後會更新。要看更新後的狀態,點擊Gause GC按鈕。

圖1.Device Monitor工具顯示[1] Update Heap和 [2] Cause GC按鈕。右邊的Heap標籤頁顯示堆的情況。

跟蹤記憶體配置

當要減少記憶體問題時,應該使用Allocation Tracker來更好的瞭解記憶體消耗大戶在哪分配。Allocation Tracker不僅在查看記憶體的具體使用上很有用,也可以分析應用中的關鍵代碼路徑,例如滑動。

例如,在應用中滑動列表時跟蹤記憶體配置,可以看到記憶體配置的動作,包括在哪些線程上分配和哪裡進行的分配。這對最佳化代碼路徑來減輕工作量和改善UI流暢性都極其有用。

使用Allocation Tracker:

1.開啟Device Monitor 。

從<sdk>/tools/路徑下載入monitor工具。

2.在DDMS視窗,從左側面板選擇應用進程。
3.在右側面板中選擇Allocation Tracker標籤頁。
4.點擊Start Tracking。
5.執行應用到需要分析的代碼路徑處。
6.點擊Get Allocations來更新分配列表。

列表顯示了所有的當前分配和512大小限制的環形緩衝區的情況。點擊行可以查看分配的堆疊追蹤資訊。堆棧不只顯示了分配的物件類型,還顯示了屬於哪個線程哪個類哪個檔案和哪一行。


圖2. Device Monitor工具顯示了在Allocation Tracker中當前應用的記憶體配置和堆疊追蹤的情況。

注意:總會有一些分配是來自與 DdmVmInternal 和 allocation tracker本身。

儘管移除掉所有嚴重影響效能的代碼是不必要的(也是不可能的),但是allocation tracker還是可以協助定位代碼中的嚴重問題。例如,應用可能在每個draw操作上建立新的Paint對象。把對象改成全域變數就是一個很簡單的改善效能的修改。

查看總體記憶體配置

為了進一步的分析,查看應用記憶體中不同記憶體類型的分配情況,可以使用下面的 adb  命令:

adb shell dumpsys meminfo <package_name>

應用當前的記憶體配置輸出資料行表,單位是KB。

當查看這些資訊時,應當熟悉下面的配置類型:

私人(Clean and Dirty) 記憶體

進程獨佔的記憶體。也就是應用進程銷毀時系統可以直接回收的記憶體容量。通常來說,“private dirty”記憶體是其最重要的部分,因為只被自己的進程使用。它只在記憶體中儲存,因此不能做分頁儲存到外存(Android不支援swap)。所有分配的Dalvik堆和本地堆都是“private dirty”記憶體;Dalvik堆和本地堆中和Zygote進程共用的部分是共用dirty記憶體。

 實際使用記憶體 (PSS)

這是另一種應用記憶體使用量的計算方式,把跨進程的共用頁也計算在內。任何獨佔的記憶體頁直接計算它的PSS值,而和其它進程共用的頁則按照共用的比例計算PSS值。例如,在兩個進程間共用的頁,計算進每個進程PPS的值是它的一半大小。

PSS計算方式的一個好處是:把所有進程的PSS值加起來就可以確定所有進程總共佔用的記憶體。這意味著用PSS來計算進程的實際記憶體使用量、進程間對比記憶體使用量和總共剩餘記憶體大小是很好的方式。

例如,下面是平板裝置中Gmail進程的輸出資訊。它顯示了很多資訊,但是具體要講解的是下面列出的一些關鍵資訊。

注意:實際看到的資訊可能和這裡的稍有不同,輸出的詳細資料可能會根據平台版本的不同而不同。

** MEMINFO in pid 9953 [com.google.android.gm] **                 Pss     Pss  Shared Private  Shared Private    Heap    Heap    Heap               Total   Clean   Dirty   Dirty   Clean   Clean    Size   Alloc    Free              ------  ------  ------  ------  ------  ------  ------  ------  ------  Native Heap      0       0       0       0       0       0    7800    7637(6)  126  Dalvik Heap   5110(3)    0    4136    4988(3)    0       0    9168    8958(6)  210 Dalvik Other   2850       0    2684    2772       0       0        Stack     36       0       8      36       0       0       Cursor    136       0       0     136       0       0       Ashmem     12       0      28       0       0       0    Other dev    380       0      24     376       0       4     .so mmap   5443(5) 1996    2584    2664(5) 5788    1996(5)    .apk mmap    235      32       0       0    1252      32    .ttf mmap     36      12       0       0      88      12    .dex mmap   3019(5) 2148       0       0    8936    2148(5)   Other mmap    107       0       8       8     324      68      Unknown   6994(4)    0     252    6992(4)    0       0        TOTAL  24358(1) 4188    9724   17972(2)16388    4260(2)16968   16595     336  Objects               Views:    426         ViewRootImpl:        3(8)         AppContexts:      6(7)        Activities:        2(7)              Assets:      2        AssetManagers:        2       Local Binders:     64        Proxy Binders:       34    Death Recipients:      0     OpenSSL Sockets:      1  SQL         MEMORY_USED:   1739  PAGECACHE_OVERFLOW:   1164          MALLOC_SIZE:       62


通常來說,只需關心Pss Total列和Private Dirty列就可以了。在一些情況下,Private Clean列和Heap Alloc列也會提供很有用的資訊。下面是一些應該查看的記憶體配置類型(行中列出的類型):

Dalvik Heap

應用中Dalvik分配使用的記憶體。Pss Total包含所有的Zygote分配(如上面PSS定義所描述的,共用跨進程的加權)。Private Dirty是應用堆獨佔的記憶體大小,包含了獨自分配的部分和應用進程從Zygote複製分裂時被修改的Zygote分配的記憶體頁。

 注意:新平台版本有Dalvik Other這一項。Dalvik Heap中的Pss Total和Private Dirty不包括Dalvik的開銷,例如即時編譯(JIT)和記憶體回收(GC),然而老版本都包含在Dalvik的開銷裡面。

 Heap Alloc是應用中Dalvik堆和本地堆已經分配使用的大小。它的值比Pss Total和Private Dirty大,因為進程是從Zygote中複製分裂出來的,包含了進程共用的分配部分。

 .so mmap和.dex mmap

mmap映射的.so(本地) 和.dex(Dalvik)代碼使用的記憶體。Pss Total 包含了跨應用共用的平台代碼;Private Clean是應用獨享的代碼。通常來說,實際映射的記憶體大小要大一點——這裡顯示的記憶體大小是執行了當前操作後應用使用的記憶體大小。然而,.so mmap 的private dirty比較大,這是由於在載入到最終地址時已經為本地代碼分配好了記憶體空間。

 Unknown

無法歸類到其它項的記憶體頁。目前,這主要包含大部分的本地分配,就是那些在工具收集資料時由於地址空間布局隨機化(Address Space Layout Randomization ,ASLR)不能被計算在內的部分。和Dalvik堆一樣, Unknown中的Pss Total把和Zygote共用的部分計算在內,Unknown中的Private Dirty只計算應用獨自使用的記憶體。

TOTAL

進程總使用的實際使用記憶體(PSS),是上面所有PSS項的總和。它表明了進程總的記憶體使用量量,可以直接用來和其它進程或總的可以記憶體進行比較。

Private Dirty和Private Clean是進程獨自佔用的總記憶體,不會和其它進程共用。當進程銷毀時,它們(特別是Private Dirty)佔用的記憶體會重新釋放回系統。Dirty記憶體是已經被修改的記憶體頁,因此必須常駐記憶體(因為沒有swap);Clean記憶體是已經映射持久檔案使用的記憶體頁(例如正在被執行的代碼),因此一段時間不使用的話就可以置換出去。

ViewRootImpl

進程中活動的根視圖的數量。每個根視圖與一個視窗關聯,因此可以協助確定涉及對話方塊和視窗的記憶體泄露。

AppContexts和Activities

當前駐留在進程中的Context和Activity對象的數量。可以很快的確認常見的由於靜態引用而不能被記憶體回收的泄露的 Activity對象。這些對象通常有很多其它相關聯的分配,因此這是追查大的記憶體泄露的很好辦法。

注意:View 和 Drawable 對象也持有所在Activity的引用,因此,持有View 或 Drawable 對象也可能會導致應用Activity泄露。

擷取堆轉儲

堆轉儲是應用堆中所有對象的快照,以二進位檔案HPROF的形式儲存。應用堆轉儲提供了應用堆的整體狀態,因此在查看堆更新的同時,可以跟蹤可能已經確認的問題。

檢索堆轉儲:

1.開啟Device Monitor。

從<sdk>/tools/路徑下載入monitor工具。

2.在DDMS視窗,從左側面板選擇應用進程。

3.點擊Dump HPROF file,顯示見圖3。

4.在彈出的視窗中,命名HPROF檔案,選擇存放位置,然後點擊Save。

圖3.Device Monitor工具顯示了[1] Dump HPROF file按鈕。

如果需要能更精確定位問題的堆轉儲,可以在應用代碼中調用dumpHprofData()來產生堆轉儲。

堆轉儲的格式基本相同,但與Java HPROF檔案不完全相同。Android堆轉儲的主要不同是由於很多的記憶體配置是在Zygote進程中。但是由於Zygote的記憶體配置是所有應用進程共用的,這些對分析應用堆沒什麼關係。

為了分析堆轉儲,你需要像jhat或Eclipse記憶體分析工具(MAT)一樣的標準工具。當然,第一步需要做的是把HPROF檔案從Android的檔案格式轉換成J2SE HRPOF的檔案格式。可以使用<sdk>/platform-tools/路徑下的hprof-conv工具來轉換。hprof-conv的使用很簡單,只要帶上兩個參數就可以:原始的HPROF檔案和轉換後的HPROF檔案的存放位置。例如:

hprof-conv heap-original.hprof heap-converted.hprof

注意:如果使用的是整合在Eclipse中的DDMS,那麼就不需要再執行HPROF轉換操作——預設已經轉換過了。

現在就可以在MAT中載入轉換過的HPROF檔案了,或者是在可以解析J2SE HPROF格式的其它堆分析工具中載入。

分析應用堆時,應該尋找由下導致的記憶體泄露:

  • 對Activity、Context、View、Drawable的長期引用,以及其它可能持有Activity或Context容器引用的對象
  • 非靜態內部類(例如持有Activity執行個體的Runnable)
  • 不必要的長期持有對象的緩衝
使用Eclipse記憶體分析工具

Eclipse記憶體分析工具(MAT)是一個可以分析堆轉儲的工具。它是一個功能相當強大的工具,功能遠遠超過這篇文檔的介紹,這裡只是一些入門的介紹。

 

在MAT中開啟類型轉換過的HPROF檔案,在總覽介面會看到一張餅狀圖,它展示了佔用堆的最大對象。在圖表下面是幾個功能的連結:

  •  Histogram view顯示所有類的列表和每個類有多少執行個體。

正常來說類的執行個體的數量應該是確定的,可以用這個視圖找到額外的類的執行個體。例如,一個常見的源碼泄露就是Activity類有額外的執行個體,而正確的是在同一時間應該只有一個執行個體。要找到特定類的執行個體,在列表頂部的<Regex>域中輸入類名尋找。

當一個類有太多的執行個體時,右擊選擇List objects>with incoming references。在顯示的列表中,通過右擊選擇Path To GC Roots> exclude weak references來確定保留的執行個體。

  • Dominator tree是按照保留堆大小來顯示的對象列表。

應該注意的是那些保留的部分堆大小粗略等於通過GC logs、heap updates或allocation tracker觀察到的泄露大小的對象。

當看到可疑項時,右擊選擇Path To GC Roots>exclude weak references。開啟新的標籤頁,標籤頁中列出了可疑泄露的對象的引用。

注意:在靠近餅狀圖中大塊堆的頂部,大部分應用會顯示Resources的執行個體,但這通常只是因為在應用使用了很多res/路徑下的資源。

圖4.MAT顯示了Histogram view和搜尋”MainActivity”的結果。

想要獲得

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.