RAM の使用状況を調査する

Android アプリを開発するときには、アプリが使うランダム アクセス メモリ(RAM)の量に常に注意を払ってください。Dalvik と ART のランタイムはルーティンのガベージ コレクション(GC)を実行しますが、アプリがいつどこにメモリを割り当てて開放するのかを理解する必要はあります。Android オペレーティング システムですばやくアプリを切り替え、安定したユーザー エクスペリエンスを提供するには、ユーザーがアプリを操作していないときはアプリで不必要にメモリを消費しないようにする必要があります。

アプリのメモリを管理するためのベスト プラクティスに従って開発時していても、オブジェクトのリークやその他のメモリに関するバグが発生する可能性はあります。アプリで使用するメモリを確実に極限まで減らすには、ここで説明するツールを使用してアプリによるメモリの使用状況を分析するしかありません。

ログ メッセージの解釈

アプリのメモリ使用状況を調査するには、まず一番シンプルなランタイム ログ メッセージから見るのがよいでしょう。GC が発生したときは、logcat でメッセージを表示できる場合があります。

Dalvik ログ メッセージ

Dalvik では、すべての GC において次の情報が logcat に出力されます(ART では出力されません)。

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

例:

D/dalvikvm( 9050): GC_CONCURRENT freed 2049K, 65% free 3571K/9991K, external 4703K/5261K, paused 2ms+2ms
GC_Reason
GC がトリガされた理由とコレクションの種類が示されます。理由には以下が含まれます。
GC_CONCURRENT
ヒープの空き領域がゼロに近づいてきたため、メモリを開放するために行うコンカレント GC です。
GC_FOR_MALLOC
ヒープに空きがない状態でアプリがメモリを割り当てようとしたため発生した GC です。システムではアプリを停止してメモリを回収する必要がありました。
GC_HPROF_DUMP_HEAP
ヒープを分析するための HPROF ファイルの作成リクエストがあったため発生した GC です。
GC_EXPLICIT
gc() の呼び出しなどによる明示的な GC です(必要時には GC が実行されると考え、このような明示的な呼び出しは避けるべきです)。
GC_EXTERNAL_ALLOC
API レベル 10 以下でのみ発生する GC です(これより新しいバージョンでは、すべて Dalvik ヒープに割り当てられます)。対象となるのは外部に割り当てられたメモリです(ネイティブ メモリまたは NIO バイト タイプのバッファに格納されたピクセルデータなど)。
Amount_freed
この GC により回収されたメモリの量。
Heap_stats
ヒープの空き容量の割合、および(ライブ オブジェクト数)/(合計ヒープサイズ)。
External_memory_stats
API レベル 10 以下で外部に割り当てられたメモリ(割り当て済みメモリの量)/(コレクションが発生する限界値)。
Pause_time
ヒープが大きいほど、一時停止時間は長くなります。コンカレント GC の場合は、コレクションの開始時と終了時間近の 2 つの停止時間が表示されます。

これらのログ メッセージが蓄積される間に、ヒープの使用率(上記の例では 3571K/9991K の値)の上昇に注目してください。この値が上昇し続ける場合は、メモリリークが発生している可能性があります。

ART ログ メッセージ

Dalvik とは異なり、ART では明示的にリクエストされなかった CG に対してはログ メッセージを記録しません。GC が出力されるのは、それが低速であるとみなされた場合のみです。正確には、GC の一時停止時間が 5 ミリ秒を超えた場合、または GC の継続時間が 100 ミリ秒を超えた場合です。アプリが一時停止を検知できるプロセス状態にない場合は、その GC が低速であるとみなされることはありません。明示的な GC はすべてログに記録されます。

ART のガベージ コレクションのログ メッセージには、以下の情報が含まれます。

I/art: <GC_Reason> <GC_Name> <Objects_freed>(<Size_freed>) AllocSpace Objects, <Large_objects_freed>(<Large_object_size_freed>) <Heap_stats> LOS objects, <Pause_time(s)>

例:

I/art : Explicit concurrent mark sweep GC freed 104710(7MB) AllocSpace objects, 21(416KB) LOS objects, 33% free, 25MB/38MB, paused 1.230ms total 67.216ms
GC_Reason
GC がトリガされた理由とコレクションの種類が示されます。理由には以下が含まれます。
Concurrent
アプリのスレッドを停止させないコンカレント GC です。この GC はバックグラウンド スレッドで実行されるため、割り当ての妨げにはなりません。
Alloc
ヒープにほとんど空きがない状態でアプリがメモリを割り当てようとしたため発生した GC です。この場合、ガベージ コレクションは割り当てスレッドで発生しています。
Explicit
アプリにより明示的にリクエストされた GC です(例: gc() または gc() の呼び出しによるリクエスト)。Dalvik と同様に ART でのベスト プラクティスは、GC に処理を委ねて、明示的な GC リクエストは極力避けることです。明示的な GC は、割り当てスレッドをブロックし、不必要に CPU サイクルを浪費するため、推奨されません。明示的な GC が別のスレッドより優先された場合は、不自然な動き(滑らかさに欠ける、振動する、アプリの停止など)の原因にもなり得ます。
NativeAlloc
Bitmaps や RenderScript 割り当てオブジェクトなど、ネイティブ割り当てによるネイティブ メモリ負荷が原因で発生した GC です。
CollectorTransition
実行時の GC の切り替えにより発生したヒープ遷移が原因の GC です。コレクターの遷移では、フリーリストで管理されたスペースからバンプポインタ スペースへ(またはその逆)すべてのオブジェクトをコピーします。現在、コレクターの遷移が発生するのは、RAM の少ない端末でアプリが処理状態を一時停止検知状態からその他の状態に変更した場合(またはその逆)のみです。
HomogeneousSpaceCompact
ホモジニアス スペース コンパクションは、フリーリスト スペースからフリー リスト スペースへのコンパクションです。これは、通常アプリが一時停止検知処理状態に遷移した場合に発生します。これを行う主な理由は、RAM 使用量の削減とヒープの断片化の解消です。
DisableMovingGc
これは実際には GC の理由ではありませんが、コンカレントのヒープ コンパクションの実行中に、GetPrimitiveArrayCritical の使用によってガベージ コレクションがブロックされていることに注意してください。GetPrimitiveArrayCritical を使うとコレクターの移動が抑止されるため、通常は使用しないことを強く推奨します。
HeapTrim
これは GC の理由ではありませんが、ヒープの削減が完了するまでガベージ コレクションがブロックされていたことに注意してください。
GC_Name
ART には、実行可能なさまざまな種類の GC があります。
Concurrent mark sweep (CMS)
イメージ スペース以外のすべてのスペースを回収するヒープ全体のコレクターです。
Concurrent partial mark sweep
イメージと Zygote のスペース以外のすべてのスペースを回収する、ヒープの大部分を対象としたコレクターです。
Concurrent sticky mark sweep
最後の GC 以降に割り当てられたオブジェクトのみを開放可能な世代別コレクターです。このガベージ コレクションは高速で一時停止が少ないため、完全または部分的なマーク&スイープよりも頻繁に実行されます。
Marksweep + semispace
ヒープの遷移およびホモジニアス スペース コンパクションに使用される、コンカレント型ではない Copying GC です。
Objects_freed
ラージ オブジェクト スペース以外で、この GC によって回収されたオブジェクトの数。
Size_freed
ラージ オブジェクト スペース以外で、この GC によって回収されたバイト数。
Large_objects_freed
ラージ オブジェクト スペース内で、この GC によって回収されたオブジェクトの数。
Large_object_size_freed
ラージ オブジェクト スペース内で、この GC によって回収されたバイト数。
Heap_stats
空き領域の割合、および(ライブ オブジェクト数)/(合計ヒープサイズ)。
Pause_time(s)
一般的に、一時停止時間は、GC の実行中に変更されたオブジェクト参照の数に比例します。現在、ART CMS GC のみ、GC の終了間近に 1 回一時停止します。Moving GC の一時停止時間は長く、GC 期間の大半にわたります。

logcat で多数の GC が確認された場合は、ヒープの使用率(上記の例では 25MB/38MB の値)の上昇に注目してください。この値が上昇し続け、減少する傾向が見られない場合は、メモリリークが発生していると考えられます。または、「Alloc」が原因で GC が発生している場合は、ヒープ容量の上限が近づいているため、近い将来に OOM 例外が発生すると予想されます。

Android Monitor へのアクセス

  1. 接続している端末またはエミュレータでアプリを起動します。
  2. [View] > [Tool Windows] > [Android Monitor] を選択します。
  3. Android Monitor の左上にある [Monitors] タブを選択します。

    図 1. Android Monitor と 3 つのモニター: MemoryCPUGPU。Android Studio で Android Monitor を垂直方向に広げると Network モニターが表示されます。

ヒープダンプの取得

ヒープダンプは、アプリのヒープ内に存在するすべてのオブジェクトのスナップショットです。ヒープダンプは HPROF と呼ばれるバイナリ形式で保存され、jhat などの分析ツールにアップロードできます。アプリのヒートダンプには、アプリのヒープ状態に関する全般的な情報が含まれているため、ヒープの更新状況を観察しているときに特定した問題を詳しく調べることができます。

  1. Memory モニターの上部で、Java ヒープのダンプアイコン をクリックします。

    Android Studio ではヒープ スナップショットをファイル名 application-id_yyyy.mm.dd_hh.mm.hprof で作成し、このファイルを Android Studio で開いて、[Captures] タブの [Heap Snapshot] リストに追加します。

  2. [Captures] タブで、ファイルを右クリックして [Export to standard .hprof] を選択します。

注: より厳密なタイミングでダンプを作成したい場合は、アプリコード内の重要な箇所で dumpHprofData() を呼び出してヒープダンプを作成することができます。

ヒープの更新状況の表示

Android Monitor を使用して、アプリを操作しながらリアルタイムでアプリのヒープの更新状況を表示できます。更新をリアルタイムで確認することで、さまざまなアプリ操作によって割り当てられるメモリ量に関する情報を取得できます。この情報をもとに、どの操作が多くのメモリを使用していて、使用メモリを減らすために調節が必要であるかを判断できます。

  1. アプリを操作して、Memory モニターで Free(空き)と Alloated(割り当て済み)のメモリを確認します。
  2. Java ヒープのダンプアイコン をクリックします。
  3. [Captures] タブでヒープ スナップショット ファイルをダブルクリックして、HPROF ビューワを開きます。
  4. ヒープの割り当てを発生させるには、アプリを操作して GC の開始アイコン をクリックします。

アプリの操作を続けて GC を開始します。各 GC によるヒープ割り当ての更新状況を観察します。アプリのどの操作が多くの割り当てを生じさせているか、割り当てを削減してリソースを開放できるのはどの部分であるかを特定します。

ヒープダンプの分析

ヒープダンプは Java HPROF ツールの形式と同様の形式で提供されますが、同一ではありません。Android ヒープダンプの主な特徴は、Zygote プロセスに多数の割り当てがあることです。Zygote 割り当てはすべてのアプリプロセスにわたって共有されるため、ヒープ分析に大きくは影響しません。

ヒープダンプの分析には、jhat などの標準ツールを使用できます。jhat を使用するには、HPROF ファイルを Android 形式から Java SE HPROF 形式に変換する必要があります。Java SE HPROF 形式に変換するには、ANDROID_SDK/platform-tools/ ディレクトリで提供される hprof-conv ツールを使用します。元の HPROF ファイルと変換済みの HPROFR ファイルの書き出し先の 2 つの引数を指定して、hprof-conv コマンドを実行します。次に例を示します。

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

これで、Java SE HPROF 形式に対応したヒープ分析ツールに、変換済みファイルをロードできます。分析を行うときには、次のいずれかが原因で生じたメモリリークに注目します。

  • ActivityContextViewDrawable、および Activity または Context コンテナへの参照を保持しているその他のオブジェクトへの長命参照。
  • Activity インスタンスを保持できる、Runnable などの静的ではない内部クラス。
  • 必要以上に長くオブジェクトを保持するキャッシュ。

メモリ割り当てのトラッキング

メモリ割り当てをトラッキングすることで、メモリを占領しているオブジェクトが割り当てられている場所をより正確に把握できるようになります。Allocation Tracker を使用して、特定のメモリ使用に注目し、スクロール操作などにおけるアプリのクリティカル コードパスを分析できます。

たとえば、Allocation tracker を使用して、アプリでリストをフリングしているときの割り当てをトラッキングできます。トラッキングによって、リストのフリングに必要なすべてのメモリ割り当て、メモリ割り当てが存在するスレッド、およびメモリ割り当ての発生元を確認できます。この種の情報をもとに実行パスを合理化すると、必要な処理量を削減できます。その結果、アプリの動作やユーザー インターフェースが全体的に改善されます。

パフォーマンスに関するクリティカル コードパスからすべてのメモリ割り当てを削除することは不要であり、不可能でもありますが、Allocation Tracker はコード内の重要な問題の特定に役立ちます。たとえば、アプリは描画時に必ず新しい Paint オブジェクトを作成する場合があります。このケースでは、Paint オブジェクトをグローバルにする修正で、簡単にパフォーマンスを改善できます。

  1. 接続している端末またはエミュレータでアプリを起動します。
  2. Android Studio で、[View] > [Tool Windows] > [Android Monitor] を選択します。
  3. Android Monitor の左上にある [Monitors] タブを選択します。
  4. Memory Monitor のツールバーで、Allocation Tracker アイコン をクリックしてメモリの割り当てを開始します。
  5. アプリを操作します。
  6. Allocation Tracker アイコン をもう一度クリックして、割り当てのトラッキングを停止します。

    Android Studio では割り当てファイルを application-id_yyyy.mm.dd_hh.mm.alloc という名前で作成し、このファイルを Android Studio で開いて、[Captures] タブの [Allocations] リストに追加します。

  7. 割り当てファイルを確認して、アプリのどのアクションによって過度の割り当てが生じる傾向にあるのかを特定し、アプリ内のどのタイミングで割り当ての削減とリソースの開放を試みるべきかを判断します。

Allocation Tracker の使用の詳細については、Allocation Tracker をご覧ください。

全体的なメモリ割り当ての表示

詳細な分析を行うには、次の adb コマンドを使用して、アプリのメモリがどのように異なるタイプの RAM 割り当てに分かれているのかを詳しく見る必要があります。

adb shell dumpsys meminfo <package_name|pid> [-d]

-d フラグを使うと、Dalvik および ART のメモリ使用状況に関連する詳細情報が出力されます。

出力では、アプリの現在のすべての割り当てがキロバイト単位で計測されて一覧表示されます。

この情報を調査するにあたり、以下のタイプの割り当てについて熟知しておく必要があります。

プライベート(クリーンおよびダーティ)RAM
これは、アプリのプロセスのみに使用されるメモリです。アプリのプロセスが破棄された場合にシステムで回収できる、RAM のまとまった領域です。通常、この領域の最も重要な部分はプライベート ダーティ RAM です。これはアプリのプロセスのみに使用され、その内容は RAM のみに存在するので、ストレージにページングできないため(Android ではスワップを使用しないため)、最も多くのリソースを消費する部分です。Dalvik およびネイティブ ヒープの割り当ては、すべてプライベート ダーティ RAM となります。Zygote プロセスと共有する Dalvik およびネイティブ割り当ては、共有ダーティ RAM です。
Proportional Set Size(PSS)
これは、プロセス間のページの共有を考慮したアプリの RAM 使用量の計測値です。プロセスに対して一意の RAM ページは、すべて PSS 値に直接反映されます。一方、他のプロセスと共有されているページは、共有量に対する比率でのみ反映されます。たとえば、2 つのプロセスで共有されているページは、そのサイズの半分が各プロセスの PSS に反映されます。

PSS 計測の優れている点は、すべてのプロセスにわたって PSS を合算することで、すべてのプロセスで使用されている実際のメモリ量を判断できることです。これは、1 つのプロセスの実際の RAM の重みの把握や、他のプロセスと RAM の使用量や使用可能な合計 RAM を比較するのに PSS が適していることを意味します。

例として、Nexus 5 端末上でのマップのプロセスの出力を次に示します。多くの情報が示されますが、重要な説明事項を以下に示します。

adb shell dumpsys meminfo com.google.android.apps.maps -d

注: プラットフォームのバージョンにより出力の詳細が一部異なるため、実際に表示される情報はここに示す内容とは若干異なる場合があります。

** MEMINFO in pid 18227 [com.google.android.apps.maps] **
                   Pss  Private  Private  Swapped     Heap     Heap     Heap
                 Total    Dirty    Clean    Dirty     Size    Alloc     Free
                ------   ------   ------   ------   ------   ------   ------
  Native Heap    10468    10408        0        0    20480    14462     6017
  Dalvik Heap    34340    33816        0        0    62436    53883     8553
 Dalvik Other      972      972        0        0
        Stack     1144     1144        0        0
      Gfx dev    35300    35300        0        0
    Other dev        5        0        4        0
     .so mmap     1943      504      188        0
    .apk mmap      598        0      136        0
    .ttf mmap      134        0       68        0
    .dex mmap     3908        0     3904        0
    .oat mmap     1344        0       56        0
    .art mmap     2037     1784       28        0
   Other mmap       30        4        0        0
   EGL mtrack    73072    73072        0        0
    GL mtrack    51044    51044        0        0
      Unknown      185      184        0        0
        TOTAL   216524   208232     4384        0    82916    68345    14570

 Dalvik Details
        .Heap     6568     6568        0        0
         .LOS    24771    24404        0        0
          .GC      500      500        0        0
    .JITCache      428      428        0        0
      .Zygote     1093      936        0        0
   .NonMoving     1908     1908        0        0
 .IndirectRef       44       44        0        0

 Objects
               Views:       90         ViewRootImpl:        1
         AppContexts:        4           Activities:        1
              Assets:        2        AssetManagers:        2
       Local Binders:       21        Proxy Binders:       28
       Parcel memory:       18         Parcel count:       74
    Death Recipients:        2      OpenSSL Sockets:        2

Gmail アプリの Dalvik の以前の dumpsys を次に示します。

** 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 割り当てにより使用される RAM です。Pss Total には、すべての Zygote 割り当て(上述の PSS の定義で説明したとおり、プロセス間の共有による重みが付けられたもの)が含まれます。Private Dirty の数値は、アプリのヒープのみにコミットされた実際の RAM です。アプリ独自の割り当てと、アプリのプロセスを Zygote からフォークした後に変更された Zygote 割り当てページで構成されます。

注: Dalvik Other セクションを持つ新しいプラットフォーム バージョンでは、Dalvik ヒープの Pss Total および Private Dirty の数値に、実行時コンパイル(Iust-In-Time Compilation、JIT)や GC ブックキーピングなどの Dalvik オーバーヘッドが含まれません。一方、古いバージョンではこれらがすべて合算されて Dalvik に表示されます。

Heap Alloc は、アプリ用に Dalvik とネイティブ ヒープ アロケータが確保しているメモリの量です。この値は、Pss Total および Private Dirty より大きくなっています。これは、プロセスが Zygote からフォークされたために、他のプロセスと共有する割り当てを含んでいるためです。

.so mmap.dex mmap
マッピングされた .so(ネイティブ)および .dex(Dalvik または ART)に使用されている RAM です。Pss Total の数値には、複数のアプリにわたり共有されているプラットフォーム コードが含まれています。Private Clean はアプリ独自のコードです。通常、実際にマッピングされたサイズはこれより大きくなります。ここに示されている RAM は、アプリにより実行されたコードの RAM に現在必要な分だけです。ただし、.so mmap には大きなプライベート ダーティが含まれます。これはネイティブ コードがその最終アドレスにロードされたときに修正されているためです。
.oat mmap
複数のアプリで共通して使用されるプリロード済みクラスに基づくコードイメージによって使用される RAM の量です。このイメージはすべてのアプリにわたって共有され、特定のアプリの影響を受けません。
.art mmap
複数のアプリで共通して使用されるプリロード済みクラスに基づくヒープイメージによって使用される RAM の量です。このイメージはすべてのアプリにわたって共有され、特定のアプリの影響を受けません。ART イメージには Object インスタンスが含まれますが、これはヒープサイズには含まれません。
.Heap(-d フラグ使用時のみ)
アプリ用のヒープメモリの量です。イメージ内のオブジェクトおよびラージ オブジェクト スペースは含まれませんが、Zygote スペースおよび非移動スペースは含まれます。
.LOS(-d フラグ使用時のみ)
ART ラージ オブジェクト スペースにより使用されている RAM の量です。これには、Zygote ラージ オブジェクトが含まれます。ラージ オブジェクトは、すべて 12 KB より大きいプリミティブ配列割り当てです。
.GC(-d フラグ使用時のみ)
アプリのオーバーヘッドに含まれる内部 CG の量です。このオーバーヘッドを削減する方法はありません。
.JITCache(-d フラグ使用時のみ)
JIT データおよびコード キャッシュにより使用されているメモリの量です。すべてのアプリがインストール時にコンパイルされるため、通常これはゼロです。
.Zygote(-d フラグ使用時のみ)
Zygote スペースで使用されているメモリの量です。Zygote スペースは端末の起動時に作成され、割り当てに使用されることはありません。
.NonMoving(-d フラグ使用時のみ)
ART 非移動スペースにより使用されている RAM の量です。非移動スペースには、フィールドやメソッドなどの移動不可能な特殊なオブジェクトが含まれます。このセクションは、アプリで使用するフィールドとメソッドを少なくすることで削減できます。
.IndirectRef(-d フラグ使用時のみ)
ART 間接参照テーブルにより使用されている RAM の量です。通常この量は少ないですが、これが大きくなった場合は、使用しているローカルおよびグローバルの JNI 参照を減らすことで、この量を削減できる可能性があります。
Unknown
より詳細な他の項目に分類できない RAM ページです。現在、この大部分を占めるのは、アドレス空間配置のランダム化(Address Space Layout Randomization、ASLR)によりデータ収集時にツールで識別できないネイティブ割り当てです。Dalvik ヒープと同様に、Unknown の Pss Total は Zygote との共有を考慮したもので、Private Dirty はアプリ専用の不明な RAM です。
TOTAL
プロセスで使用される Proportional Set Size(PSS)RAM の合計です。これの上に表示されているすべての PSS フィールドの合計となります。プロセス全体のメモリの重みを表し、他のプロセスや使用可能な合計 RAM と直接比較できます。

Private Dirty および Private Clean は、他のプロセスと共有されていないプロセス内の割り当ての合計です。この 2 つを合わせたものが(大部分が Private Dirty)、プロセスが破棄されたときにシステムに開放される RAM の量となります。ダーティ RAM は変更されたページであり、RAM にコミットされたまま維持される必要があります(スワップがないため)。クリーン RAM は永続ファイル(実行されるコードなど)からマッピングされたページであり、一定期間使用されない場合はページアウトが可能です。

ViewRootImpl
プロセスでアクティブなルートビューの数です。各ルートビューはウィンドウと関連付けられているため、ダイアログやその他のウィンドウに関連するメモリリークの特定に役立ちます。
AppContextsActivities
プロセスで現在ライブ状態にある、アプリの Context オブジェクトおよび Activity オブジェクトの数です。これにより、一般的な現象である、静的な参照があるためにガベージ コレクションの対象とならないリークした Activity オブジェクトを簡単に特定できるようになります。通常、これらのオブジェクトには関連付けられたその他の割り当てが多くあるため、これらのオブジェクによって大きなメモリリークを追跡できるようになります。

注: View または Drawable オブジェクトは、その所属元である Activity への参照を保持しています。そのため、View または Drawable オブジェクトを保持すると、アプリが Activity をリークする原因となり得ます。

メモリリークのトリガ

上述のツールを使用するときは、アプリコードに過度な負荷をかけて、メモリリークを強制的に発生させる必要があります。アプリでメモリリークを発生させるには、ヒープを調査する前にしばらくの間アプリを実行するという方法があります。リークは、ヒープ内の割り当ての先頭に徐々に出現してきます。ただし、リークが少ない場合は、検出できるまで長時間アプリを実行する必要があります。

次のいずれかの方法で、メモリリークをトリガすることも可能です。

  1. 異なるアクティビティ状態で、端末を縦表示から横表示に回転させてから元に戻す動作を複数回行います。デバイスを回転させると、ActivityContext、または View オブジェクトのリークがアプリで発生することがよくあります。これは、システムにより Activity が再作成され、これらのいずれかのオブジェクトへの参照がどこか別の場所で保持されている場合、システムはこのようなオブジェクトをガベージ コレクションの対象にできないためです。
  2. さまざまなアクティビティ状態で、自分のアプリと別のアプリを切り替えます(ホーム画面に移動してから自分のアプリに戻るなど)。

ヒント: 上述の手順は、Monkey テスト フレームワークを使用しても実行できます。Monkey テスト フレームワークの実行の詳細については、monkeyrunner のドキュメントをご覧ください。