Android內存優化(四)解析Memory Monitor、Allocation Tracker和Heap Dump

相關文章
Android性能優化系列
Java虛擬機系列html

前言

要想作好內存優化工做,就要掌握兩大部分的知識,一部分是知道並理解內存優化相關的原理,另外一部分就是善於運用內存分析的工具。本篇就來介紹內存分析工具:Memory Monitor、Allocation Tracker和Heap Dump的使用方法。java

1.Memory Monitor

在Android Studio(如下簡稱AS)中Android Monitor是一個主窗口,它包含了Logcat,、Memory Monitor、CPU Monitor、 GPU Monitor和Network Monitor。其中Memory Monitor能夠輕鬆地監視應用程序的性能和內存使用狀況,以便於找到被分配的對象,定位內存泄漏,並跟蹤鏈接設備中正在使用的內存數量。Memory Monitor能夠報告出你的應用程序的內存分配狀況, 更形象的呈現出應用程序使用的內存。它的做用以下:android

  • 實時顯示可用的和分配的Java內存的圖表。
  • 實時顯示垃圾收集(GC)事件。
  • 啓動垃圾收集事件。
  • 快速測試應用程序的緩慢是否與過分的垃圾收集事件有關。
  • 快速測試應用程序崩潰是否與內存耗盡有關。

1.1 使用Memory Monitor

在使用Memory Monitor以前要確保手機開啓了開發者模式和USB調試。
使用的步驟爲:
1.運行須要監控的應用程序。
2.點擊AS面板下面的Android圖標,並選擇Monitors選項。
若是Memory Monitor已經運行,效果以下圖所示(AS版本2.3.2)。
數組

圖中的標註的功能以下:性能優化

  • Initiate GC(標識1):用來手動觸發GC。
  • Dump Java heap(標識2):保存內存快照。
  • Start/Stop Allocation Tracking(標識3):打開Allocation Tracker工具(後面會介紹)。
  • Free(標識4):當前應用未分配的內存大小。
  • Allocated(標識5):當前應用分配的內存大小。

圖中y軸顯示當前應用的分配的內存和未分配的內存大小;x軸表示通過的時間。微信

1.2 大內存申請與GC

從上圖能夠看出,分配的內存急劇上升,這就是大內存分配的場景,咱們要判斷這是不是合理的分配的內存,是Bitmap仍是其餘的大數據,而且對這種大數據進行優化,減小內存開銷。
接下來分配的內存出現急劇降低,這表示垃圾收集事件,用來釋放內存。ide

1.3 內存抖動

內存抖動通常指在很短的時間內發生了屢次內存分配和釋放,嚴重的內存抖動還會致使應用程序卡頓。內存抖動出現緣由主要是短期頻繁的建立對象(可能在循環中建立對象),內存爲了應對這種狀況,也會頻繁的進行GC,所以綜合起來就產生了內存抖動,產生了如上圖般的鋸齒狀。工具

2.Allocation Tracker

Allocation Tracker用來跟蹤內存分配,它容許你在執行某些操做的同時監視在何處分配對象,瞭解這些分配使你可以調整與這些操做相關的方法調用,以優化應用程序性能和內存使用。
Allocation Tracker可以作到以下的事情:性能

  • 顯示代碼分配對象類型、大小、分配線程和堆棧跟蹤的時間和位置。
  • 經過重複的分配/釋放模式幫助識別內存變化。
  • 當與 HPROF Viewer結合使用時,能夠幫助你跟蹤內存泄漏。例如,若是你在堆上看到一個bitmap對象,你可使用Allocation Tracker來找到其分配的位置。

2.1 使用Allocation Tracker

AS和DDMS中都有Allocation Tracker,這裏會·介紹AS中的Allocation Tracke如何使用。首先要確保要確保手機開啓了開發者模式,而且開啓了USB調試。
使用的步驟爲:
1.運行須要監控的應用程序。
2.點擊AS面板下面的Android圖標,並選擇Monitors選項。
3.點擊Start Allocation Tracking按鈕,這時Start Allocation Tracking按鈕變爲了Stop Allocation Tracking按鈕。
4.操做應用程序。
5.點擊Stop Allocation Tracking按鈕,結束快照。這時Memory Monitor會顯示出捕獲快照的期間,以下圖所示。
測試

6.過幾秒後就會自動打開一個窗口,顯示當前生成的alloc文件的內存數據。

2.2 alloc文件分析

自動打開的alloc文件窗口以下圖所示。

該alloc文件顯示如下信息:

說明
Method 負責分配的Java方法
Count 分配的實例總數
Total Size 分配內存的總字節數

接着咱們來分析標紅框的內容,負責分配的Java方法爲performLaunchActivity,內存分配序列爲2369,分配的對象爲ActivityThread,分配的實例總數爲300個,分配內存的總字節數爲10512。不瞭解performLaunchActivity方法和ActivityThread能夠看Android深刻四大組件這一系列的文章。

目前的菜單選項是Group by Method咱們也能夠選擇 Group By Allocator,以下圖所示。

爲了更好的解釋圖中的信息,這裏給出測試的代碼,MainActivity和SecondActivity 的代碼以下所示。
MainActivity.java

public class MainActivity extends AppCompatActivity {
    private Button button;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        button =(Button)findViewById(R.id.bt_next);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(MainActivity.this,SecondActivity.class));
            }
        });
    }
}複製代碼

SecondActivity.java

public class SecondActivity extends AppCompatActivity {
    private static Object inner;
    private Button button;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        button = (Button) findViewById(R.id.bt_next);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                createInnerClass();
                finish();
            }
        });
    }
    void createInnerClass() {
        class InnerClass {
        }
        inner = new InnerClass();
    }
}複製代碼

其中SecondActivity是存在內存泄漏的,生成快照期間,個人操做就是在MainActivity和SecondActivity跳轉了3次(點擊button 共6次)。這時咱們回過頭來看上圖的紅框的信息,MainActivity總共分配了3個Intent實例,佔用內存爲192字節。SecondActivity總共分配了6個實例,佔用內存爲96字節,其中分配了3個匿名內部類OnClickListener的實例,3個InnerClass的實例。

咱們能夠選擇列表中的一項,單擊鼠標右鍵,在彈出的菜單中選擇jump to the source就能夠跳轉到對應的源文件中。
除此以外,還能夠點擊Show/Hide Chart按鈕來顯示數據的圖形化,以下圖所示。

3.Heap Dump

Heap Dump的主要功能就是查看不一樣的數據類型在內存中的使用狀況。它能夠幫助你找到大對象,也能夠經過數據的變化發現內存泄漏。

3.1 使用Heap Dump

打開Android Device Monitor工具,在左邊Devices列表中選擇要查看的應用程序進程,點擊Update Heap按鈕(裝有一半綠色液體的圓柱體),在右邊選擇Heap選項,並點擊Cause GC按鈕,就會開始顯示數據。咱們每次點擊Cause GC按鈕都會強制應用程序進行垃圾回收,並將清理後的數據顯示在Heap工具中。以下圖所示。

從上圖能夠看出,Heap工具共有三個區域,分別是總覽視圖(標識1)、詳情視圖(標識2)和內存分配柱狀圖(標識2)。

3.2 總覽視圖

其中總覽視圖能夠查看總體的內存狀況,表中的顯示信息以下所示。

說明
Heap Size 堆棧分配給該應用程序的內存大小
Allocated 已分配使用的內存大小
Free 空閒的內存大小
%Used 當前Heap的使用率(Allocated/Heap Size)
#Objects 對象的數量

結合上表和上圖,咱們在總覽視圖得到的信息就是:堆棧分配給當前的應用程序的內存大小爲2.346MB,已分配的內存爲1.346MB,空閒的內存爲1MB,當前Heap的使用率爲57.37%,對象的數量爲24058個。

3.3 詳情視圖

詳細視圖展現了全部的數據類型的內存狀況,表中列的信息以下所示。

說明
Type 數據類型
Total Size 總共佔用的內存大小
Smallest 將該數據類型的對象從小到大排列,排在第一個的對象所佔用的內存
Largest 將該數據類型的對象從小到大排列,排在最後一個的對象所佔用的內存
Median 將該數據類型的對象從小到大排列,排在中間的對象所佔用的內存
Average 該數據類型的對象所佔用內存的平均值

除了列的信息,還有行信息:

說明
free 內存碎片
data object 對象
class object
1-byte array (byte[],boolean[]) 1字節的數組對象
2-byte array (short[],char[]) 2字節的數組對象
4-byte array (object[],int[],float[]) 4字節的數組對象
6-byte array (long[],double[]) 8字節的數組對象
non-Java object 非Java對象

行信息中比較重要的是free,它與總覽視圖中的free的含義不一樣,它表明內存碎片。當新建立一個對象時,若是碎片內存能容下該對象,則複用碎片內存,不然就會從free空間(總覽視圖中的free)從新劃份內存給這個新對象。free是判斷內存碎片化程度的一個重要的指標。
此外,1-byte array這一行的信息也很重要,由於圖片是以byte[]的形式存儲在內存中的,若是1-byte array一行的數據過大,則須要檢查圖片的內存管理了。

3.4 檢測內存泄漏

Heap Dump也能夠檢測內存泄漏。在左邊Devices列表中選擇要查看的應用程序進程,點擊Update Heap按鈕(裝有一半綠色液體的圓柱體),在右邊選擇Heap選項,並點擊Cause GC按鈕,就會開始顯示數據,以下圖所示。

這時data object的Total Size爲270.266KB。接下來操做應用,這個應用仍舊是在2.2小節所舉的內存泄漏的例子,我反覆的在MainActivity和SecondActivity跳轉了10次(點擊Button共20次),數據顯示爲:

data object的Total Size變爲了768.172KB。這時我點擊Cause GC按鈕,數據顯示爲:

能夠看到data object的Total Size變爲了444.516KB,再點擊一次Cause GC按鈕:

Total Size變爲了323.312KB,通過兩次Cause GC的操做,Total Size的值從768.172KB變爲了323.312KB,這是一個比較大的變化,說明在Cause GC操做以前有462.86KB(768.172KB-323.312KB)的內存沒有被回收,可能發生了內存泄漏。

參考資料
Memory Monitor
Allocation Tracker
Android Monitor Basics
Android性能專項測試之Memory Monitor工具
《Android應用性能優化最佳實踐》
《Android羣英傳 神兵利器》
《高性能Android應用開發》


個人新書《Android進階之光》已出版,查看詳情點擊這
歡迎關注個人微信公衆號,第一時間得到博客更新提醒,以及更多成體系的Android相關原創技術乾貨。
掃一掃下方二維碼或者長按識別二維碼,便可關注。

相關文章
相關標籤/搜索