495 lines
24 KiB
Plaintext
495 lines
24 KiB
Plaintext
page.title=Investigating Your RAM Usage
|
||
page.tags="memory","OutOfMemoryError"
|
||
@jd:body
|
||
|
||
<div id="qv-wrapper">
|
||
<div id="qv">
|
||
<h2>In this document</h2>
|
||
<ol>
|
||
<li><a href="#LogMessages">Interpreting Log Messages</a></li>
|
||
<li><a href="#ViewHeap">Viewing Heap Updates</a></li>
|
||
<li><a href="#TrackAllocations">Tracking Allocations</a></li>
|
||
<li><a href="#ViewingAllocations">Viewing Overall Memory Allocations</a></li>
|
||
<li><a href="#HeapDump">Capturing a Heap Dump</a></li>
|
||
<li><a href="#TriggerLeaks">Triggering Memory Leaks</a></li>
|
||
</ol>
|
||
<h2>See Also</h2>
|
||
<ul>
|
||
<li><a href="{@docRoot}training/articles/memory.html">Managing Your App's Memory</a></li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
|
||
|
||
<p>Because Android is designed for mobile devices, you should always be careful about how much
|
||
random-access memory (RAM) your app uses. Although Android’s Dalvik virtual machine performs
|
||
routine garbage collection, this doesn’t mean you can ignore when and where your app allocates and
|
||
releases memory. In order to provide a stable user experience that allows the system to quickly
|
||
switch between apps, it’s important that your app does not needlessly consume memory when the user
|
||
is not interacting with it.</p>
|
||
|
||
<p>Even if you follow all the best practices for <a href="{@docRoot}training/articles/memory.html"
|
||
>Managing Your App Memory</a> during
|
||
development (which you should), you still might leak objects or introduce other memory bugs. The
|
||
only way to be certain your app is using as little memory as possible is to analyze your app’s
|
||
memory usage with tools. This guide shows you how to do that.</p>
|
||
|
||
|
||
<h2 id="LogMessages">Interpreting Log Messages</h2>
|
||
|
||
<p>The simplest place to begin investigating your apps memory usage is the Dalvik log messages. You'll
|
||
find these log messages in <a href="{@docRoot}tools/help/logcat.html">logcat</a> (the output is
|
||
available in the Device Monitor or directly in IDEs such as Eclipse and Android Studio).</p>
|
||
|
||
<p>Every time a garbage collection occurs, logcat prints a message with the following information:</p>
|
||
|
||
<pre class="no-pretty-print">
|
||
D/dalvikvm: <GC_Reason> <Amount_freed>, <Heap_stats>, <External_memory_stats>, <Pause_time>
|
||
</pre>
|
||
|
||
<dl>
|
||
<dt>GC Reason</dt>
|
||
<dd>
|
||
What triggered the garbage collection and what kind of collection it is. Reasons that may appear
|
||
include:
|
||
<dl>
|
||
<dt><code>GC_CONCURRENT</code></dt>
|
||
<dd>A concurrent garbage collection that frees up memory as your heap begins to fill up.</dd>
|
||
|
||
<dt><code>GC_FOR_MALLOC</code></dt>
|
||
<dd>A garbage collection caused because your app attempted to allocate memory when your heap was
|
||
already full, so the system had to stop your app and reclaim memory.</dd>
|
||
|
||
<dt><code>GC_HPROF_DUMP_HEAP</code></dt>
|
||
<dd>A garbage collection that occurs when you create an HPROF file to analyze your heap.</dd>
|
||
|
||
<dt><code>GC_EXPLICIT</code>
|
||
<dd>An explicit garbage collection, such as when you call {@link java.lang.System#gc()} (which you
|
||
should avoid calling and instead trust the garbage collector to run when needed).</dd>
|
||
|
||
<dt><code>GC_EXTERNAL_ALLOC</code></dt>
|
||
<dd>This happens only on API level 10 and lower (newer versions allocate everything in the Dalvik
|
||
heap). A garbage collection for externally allocated memory (such as the pixel data stored in
|
||
native memory or NIO byte buffers).</dd>
|
||
</dl>
|
||
</dd>
|
||
|
||
<dt>Amount freed</dt>
|
||
<dd>The amount of memory reclaimed from this garbage collection.</dd>
|
||
|
||
<dt>Heap stats</dt>
|
||
<dd>Percentage free and (number of live objects)/(total heap size).</dd>
|
||
|
||
<dt>External memory stats</dt>
|
||
<dd>Externally allocated memory on API level 10 and lower (amount of allocated memory) / (limit at
|
||
which collection will occur).</dd>
|
||
|
||
<dt>Pause time</dt>
|
||
<dd>Larger heaps will have larger pause times. Concurrent pause times show two pauses: one at the
|
||
beginning of the collection and another near the end.</dd>
|
||
</dl>
|
||
|
||
<p>For example:</p>
|
||
|
||
<pre class="no-pretty-print">
|
||
D/dalvikvm( 9050): GC_CONCURRENT freed 2049K, 65% free 3571K/9991K, external 4703K/5261K, paused 2ms+2ms
|
||
</pre>
|
||
|
||
<p>As these log messages stack up, look out for increases in the heap stats (the
|
||
{@code 3571K/9991K} value in the above example). If this value
|
||
continues to increase and doesn't ever seem to get smaller, you could have a memory leak.</p>
|
||
|
||
|
||
<h2 id="ViewHeap">Viewing Heap Updates</h2>
|
||
|
||
<p>To get a little information about what kind of memory your app is using and when, you can view
|
||
real-time updates to your app's heap in the Device Monitor:</p>
|
||
|
||
<ol>
|
||
<li>Open the Device Monitor.
|
||
<p>From your <code><sdk>/tools/</code> directory, launch the <code>monitor</code> tool.</p>
|
||
</li>
|
||
<li>In the Debug Monitor window, select your app's process from the list on the left.</li>
|
||
<li>Click <strong>Update Heap</strong> above the process list.</li>
|
||
<li>In the right-side panel, select the <strong>Heap</strong> tab.</li>
|
||
</ol>
|
||
|
||
<p>The Heap view shows some basic stats about your heap memory usage, updated after every
|
||
garbage collection. To see the first update, click the <strong>Cause GC</strong> button.</p>
|
||
|
||
<img src="{@docRoot}images/tools/monitor-vmheap@2x.png" width="760" alt="" />
|
||
<p class="img-caption"><strong>Figure 1.</strong> The Device Monitor tool,
|
||
showing the <strong>[1] Update Heap</strong> and <strong>[2] Cause GC</strong> buttons.
|
||
The Heap tab on the right shows the heap results.</p>
|
||
|
||
<p>Continue interacting with your app to watch your heap allocation update with each garbage
|
||
collection. This can help you identify which actions in your app are likely causing too much
|
||
allocation and where you should try to reduce allocations and release
|
||
resources.</p>
|
||
|
||
|
||
|
||
<h2 id="TrackAllocations">Tracking Allocations</h2>
|
||
|
||
<p>As you start narrowing down memory issues, you should also use the Allocation Tracker to
|
||
get a better understanding of where your memory-hogging objects are allocated. The Allocation
|
||
Tracker can be useful not only for looking at specific uses of memory, but also to analyze critical
|
||
code paths in an app such as scrolling.</p>
|
||
|
||
<p>For example, tracking allocations when flinging a list in your app allows you to see all the
|
||
allocations that need to be done for that behavior, what thread they are on, and where they came
|
||
from. This is extremely valuable for tightening up these paths to reduce the work they need and
|
||
improve the overall smoothness of the UI.</p>
|
||
|
||
<p>To use Allocation Tracker:</p>
|
||
<ol>
|
||
<li>Open the Device Monitor.
|
||
<p>From your <code><sdk>/tools/</code> directory, launch the <code>monitor</code> tool.</p>
|
||
</li>
|
||
<li>In the DDMS window, select your app's process in the left-side panel.</li>
|
||
<li>In the right-side panel, select the <strong>Allocation Tracker</strong> tab.</li>
|
||
<li>Click <strong>Start Tracking</strong>.</li>
|
||
<li>Interact with your app to execute the code paths you want to analyze.</li>
|
||
<li>Click <strong>Get Allocations</strong> every time you want to update the
|
||
list of allocations.</li>
|
||
</ol>
|
||
|
||
<p>The list shows all recent allocations,
|
||
currently limited by a 512-entry ring buffer. Click on a line to see the stack trace that led to
|
||
the allocation. The trace shows you not only what type of object was allocated, but also in which
|
||
thread, in which class, in which file and at which line.</p>
|
||
|
||
<img src="{@docRoot}images/tools/monitor-tracker@2x.png" width="760" alt="" />
|
||
<p class="img-caption"><strong>Figure 2.</strong> The Device Monitor tool,
|
||
showing recent app allocations and stack traces in the Allocation Tracker.</p>
|
||
|
||
|
||
<p class="note"><strong>Note:</strong> You will always see some allocations from {@code
|
||
DdmVmInternal} and else where that come from the allocation tracker itself.</p>
|
||
|
||
<p>Although it's not necessary (nor possible) to remove all allocations for your performance
|
||
critical code paths, the allocation tracker can help you identify important issues in your code.
|
||
For instance, some apps might create a new {@link android.graphics.Paint} object on every draw.
|
||
Moving that object into a global member is a simple fix that helps improve performance.</p>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<h2 id="ViewingAllocations">Viewing Overall Memory Allocations</h2>
|
||
|
||
<p>For further analysis, you may want to observe how your app's memory is
|
||
divided between different types of RAM allocation with the
|
||
following <a href="{@docRoot}tools/help/adb.html">adb</a> command:</p>
|
||
|
||
<pre class="no-pretty-print">
|
||
adb shell dumpsys meminfo <package_name>
|
||
</pre>
|
||
|
||
<p>The output lists all of your app's current allocations, measured in kilobytes.</p>
|
||
|
||
<p>When inspecting this information, you should be familiar with the
|
||
following types of allocation:</p>
|
||
|
||
<dl>
|
||
<dt>Private (Clean and Dirty) RAM</dt>
|
||
<dd>This is memory that is being used by only your process. This is the bulk of the RAM that the system
|
||
can reclaim when your app’s process is destroyed. Generally, the most important portion of this is
|
||
“private dirty” RAM, which is the most expensive because it is used by only your process and its
|
||
contents exist only in RAM so can’t be paged to storage (because Android does not use swap). All
|
||
Dalvik and native heap allocations you make will be private dirty RAM; Dalvik and native
|
||
allocations you share with the Zygote process are shared dirty RAM.</dd>
|
||
|
||
<dt>Proportional Set Size (PSS)</dt>
|
||
<dd>This is a measurement of your app’s RAM use that takes into account sharing pages across processes.
|
||
Any RAM pages that are unique to your process directly contribute to its PSS value, while pages
|
||
that are shared with other processes contribute to the PSS value only in proportion to the amount
|
||
of sharing. For example, a page that is shared between two processes will contribute half of its
|
||
size to the PSS of each process.</dd>
|
||
</dl>
|
||
|
||
|
||
<p>A nice characteristic of the PSS measurement is that you can add up the PSS across all processes to
|
||
determine the actual memory being used by all processes. This means PSS is a good measure for the
|
||
actual RAM weight of a process and for comparison against the RAM use of other processes and the
|
||
total available RAM.</p>
|
||
|
||
|
||
<p>For example, below is the the output for Gmail’s process on a tablet device. There is a lot of
|
||
information here, but key points for discussion are listed below.</p>
|
||
|
||
<p class="note"><strong>Note:</strong> The information you see may vary slightly from what is shown
|
||
here, as some details of the output differ across platform versions.</p>
|
||
|
||
<pre class="no-pretty-print">
|
||
** 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
|
||
</pre>
|
||
|
||
<p>Generally, you should be concerned with only the <code>Pss Total</code> and <code>Private Dirty</code>
|
||
columns. In some cases, the <code>Private Clean</code> and <code>Heap Alloc</code> columns also offer
|
||
interesting data. Here is some more information about the different memory allocations (the rows)
|
||
you should observe:
|
||
|
||
<dl>
|
||
<dt><code>Dalvik Heap</code></dt>
|
||
<dd>The RAM used by Dalvik allocations in your app. The <code>Pss Total</code> includes all Zygote
|
||
allocations (weighted by their sharing across processes, as described in the PSS definition above).
|
||
The <code>Private Dirty</code> number is the actual RAM committed to only your app’s heap, composed of
|
||
your own allocations and any Zygote allocation pages that have been modified since forking your
|
||
app’s process from Zygote.
|
||
|
||
<p class="note"><strong>Note:</strong> On newer platform versions that have the <code>Dalvik
|
||
Other</code> section, the <code>Pss Total</code> and <code>Private Dirty</code> numbers for Dalvik Heap do
|
||
not include Dalvik overhead such as the just-in-time compilation (JIT) and garbage collection (GC)
|
||
bookkeeping, whereas older versions list it all combined under <code>Dalvik</code>.</p>
|
||
|
||
<p>The <code>Heap Alloc</code> is the amount of memory that the Dalvik and native heap allocators keep
|
||
track of for your app. This value is larger than <code>Pss Total</code> and <code>Private Dirty</code>
|
||
because your process was forked from Zygote and it includes allocations that your process shares
|
||
with all the others.</p>
|
||
</dd>
|
||
|
||
<dt><code>.so mmap</code> and <code>.dex mmap</code></dt>
|
||
<dd>The RAM being used for mmapped <code>.so</code> (native) and <code>.dex</code> (Dalvik) code. The
|
||
<code>Pss Total</code> number includes platform code shared across apps; the <code>Private Clean</code> is
|
||
your app’s own code. Generally, the actual mapped size will be much larger—the RAM here is only
|
||
what currently needs to be in RAM for code that has been executed by the app. However, the .so mmap
|
||
has a large private dirty, which is due to fix-ups to the native code when it was loaded into its
|
||
final address.
|
||
</dd>
|
||
|
||
<dt><code>Unknown</code></dt>
|
||
<dd>Any RAM pages that the system could not classify into one of the other more specific items.
|
||
Currently, this contains mostly native allocations, which cannot be identified by the tool when
|
||
collecting this data due to Address Space Layout Randomization (ASLR). As with the Dalvik heap, the
|
||
<code>Pss Total</code> for Unknown takes into account sharing with Zygote, and <code>Private Dirty</code>
|
||
is unknown RAM dedicated to only your app.
|
||
</dd>
|
||
|
||
<dt><code>TOTAL</code></dt>
|
||
<dd>The total Proportional Set Size (PSS) RAM used by your process. This is the sum of all PSS fields
|
||
above it. It indicates the overall memory weight of your process, which can be directly compared
|
||
with other processes and the total available RAM.
|
||
|
||
<p>The <code>Private Dirty</code> and <code>Private Clean</code> are the total allocations within your
|
||
process, which are not shared with other processes. Together (especially <code>Private Dirty</code>),
|
||
this is the amount of RAM that will be released back to the system when your process is destroyed.
|
||
Dirty RAM is pages that have been modified and so must stay committed to RAM (because there is no
|
||
swap); clean RAM is pages that have been mapped from a persistent file (such as code being
|
||
executed) and so can be paged out if not used for a while.</p>
|
||
|
||
</dd>
|
||
|
||
<dt><code>ViewRootImpl</code></dt>
|
||
<dd>The number of root views that are active in your process. Each root view is associated with a
|
||
window, so this can help you identify memory leaks involving dialogs or other windows.
|
||
</dd>
|
||
|
||
<dt><code>AppContexts</code> and <code>Activities</code></dt>
|
||
<dd>The number of app {@link android.content.Context} and {@link android.app.Activity} objects that
|
||
currently live in your process. This can be useful to quickly identify leaked {@link
|
||
android.app.Activity} objects that can’t be garbage collected due to static references on them,
|
||
which is common. These objects often have a lot of other allocations associated with them and so
|
||
are a good way to track large memory leaks.</dd>
|
||
|
||
<p class="note"><strong>Note:</strong> A {@link android.view.View} or {@link
|
||
android.graphics.drawable.Drawable} object also holds a reference to the {@link
|
||
android.app.Activity} that it's from, so holding a {@link android.view.View} or {@link
|
||
android.graphics.drawable.Drawable} object can also lead to your app leaking an {@link
|
||
android.app.Activity}.</p>
|
||
|
||
</dd>
|
||
</dl>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<h2 id="HeapDump">Capturing a Heap Dump</h2>
|
||
|
||
<p>A heap dump is a snapshot of all the objects in your app's heap, stored in a binary format called
|
||
HPROF. Your app's heap dump provides information about the overall state of your app's heap so you
|
||
can track down problems you might have identified while viewing heap updates.</p>
|
||
|
||
<p>To retrieve your heap dump:</p>
|
||
<ol>
|
||
<li>Open the Device Monitor.
|
||
<p>From your <code><sdk>/tools/</code> directory, launch the <code>monitor</code> tool.</p>
|
||
</li>
|
||
<li>In the DDMS window, select your app's process in the left-side panel.</li>
|
||
<li>Click <strong>Dump HPROF file</strong>, shown in figure 3.</li>
|
||
<li>In the window that appears, name your HPROF file, select the save location,
|
||
then click <strong>Save</strong>.</li>
|
||
</ol>
|
||
|
||
<img src="{@docRoot}images/tools/monitor-hprof@2x.png" width="760" alt="" />
|
||
<p class="img-caption"><strong>Figure 3.</strong> The Device Monitor tool,
|
||
showing the <strong>[1] Dump HPROF file</strong> button.</p>
|
||
|
||
<p>If you need to be more precise about when the dump is created, you can also create a heap dump
|
||
at the critical point in your app code by calling {@link android.os.Debug#dumpHprofData
|
||
dumpHprofData()}.</p>
|
||
|
||
<p>The heap dump is provided in a format that's similar to, but not identical to one from the Java
|
||
HPROF tool. The major difference in an Android heap dump is due to the fact that there are a large
|
||
number of allocations in the Zygote process. But because the Zygote allocations are shared across
|
||
all app processes, they don’t matter very much to your own heap analysis.</p>
|
||
|
||
<p>To analyze your heap dump, you can use a standard tool like jhat or the <a href=
|
||
"http://www.eclipse.org/mat/downloads.php">Eclipse Memory Analyzer Tool</a> (MAT). However, first
|
||
you'll need to convert the HPROF file from Android's format to the J2SE HPROF format. You can do
|
||
this using the <code>hprof-conv</code> tool provided in the <code><sdk>/tools/</code>
|
||
directory. Simply run the <code>hprof-conv</code> command with two arguments: the original HPROF
|
||
file and the location to write the converted HPROF file. For example:</p>
|
||
|
||
<pre class="no-pretty-print">
|
||
hprof-conv heap-original.hprof heap-converted.hprof
|
||
</pre>
|
||
|
||
<p class="note"><strong>Note:</strong> If you're using the version of DDMS that's integrated into
|
||
Eclipse, you do not need to perform the HPROF converstion—it performs the conversion by
|
||
default.</p>
|
||
|
||
<p>You can now load the converted file in MAT or another heap analysis tool that understands
|
||
the J2SE HPROF format.</p>
|
||
|
||
<p>When analyzing your heap, you should look for memory leaks caused by:</p>
|
||
<ul>
|
||
<li>Long-lived references to an Activity, Context, View, Drawable, and other objects that may hold a
|
||
reference to the container Activity or Context.</li>
|
||
<li>Non-static inner classes (such as a Runnable, which can hold the Activity instance).</li>
|
||
<li>Caches that hold objects longer than necessary.</li>
|
||
</ul>
|
||
|
||
|
||
<h3 id="EclipseMat">Using the Eclipse Memory Analyzer Tool</h3>
|
||
|
||
<p>The <a href=
|
||
"http://www.eclipse.org/mat/downloads.php">Eclipse Memory Analyzer Tool</a> (MAT) is just one
|
||
tool that you can use to analyze your heap dump. It's also quite powerful so most of its
|
||
capabilities are beyond the scope of this document, but here are a few tips to get you started.
|
||
|
||
<p>Once you open your converted HPROF file in MAT, you'll see a pie chart in the Overview,
|
||
showing what your largest objects are. Below this chart, are links to couple of useful features:</p>
|
||
|
||
<ul>
|
||
<li>The <strong>Histogram view</strong> shows a list of all classes and how many instances
|
||
there are of each.
|
||
<p>You might want to use this view to find extra instances of classes for which you know there
|
||
should be only a certain number. For example, a common source of leaks is additional instance of
|
||
your {@link android.app.Activity} class, for which you should usually have only one instance
|
||
at a time. To find a specific class instance, type the class name into the <em><Regex></em>
|
||
field at the top of the list.
|
||
<p>When you find a class with too many instances, right-click it and select
|
||
<strong>List objects</strong> > <strong>with incoming references</strong>. In the list that
|
||
appears, you can determine where an instance is retained by right-clicking it and selecting
|
||
<strong>Path To GC Roots</strong> > <strong>exclude weak references</strong>.</p>
|
||
</li>
|
||
|
||
<li>The <strong>Dominator tree</strong> shows a list of objects organized by the amount
|
||
of retained heap.
|
||
<p>What you should look for is anything that's retaining a portion of heap that's roughly
|
||
equivalent to the memory size you observed leaking from the <a href="#LogMessages">GC logs</a>,
|
||
<a href="#ViewHeap">heap updates</a>, or <a href="#TrackAllocations">allocation
|
||
tracker</a>.
|
||
<p>When you see something suspicious, right-click on the item and select
|
||
<strong>Path To GC Roots</strong> > <strong>exclude weak references</strong>. This opens a
|
||
new tab that traces the references to that object which is causing the alleged leak.</p>
|
||
|
||
<p class="note"><strong>Note:</strong> Most apps will show an instance of
|
||
{@link android.content.res.Resources} near the top with a good chunk of heap, but this is
|
||
usually expected when your app uses lots of resources from your {@code res/} directory.</p>
|
||
</li>
|
||
</ul>
|
||
|
||
|
||
<img src="{@docRoot}images/tools/mat-histogram@2x.png" width="760" alt="" />
|
||
<p class="img-caption"><strong>Figure 4.</strong> The Eclipse Memory Analyzer Tool (MAT),
|
||
showing the Histogram view and a search for "MainActivity".</p>
|
||
|
||
<p>For more information about MAT, watch the Google I/O 2011 presentation,
|
||
<a href="http://www.youtube.com/watch?v=_CruQY55HOk">Memory management for Android apps</a>,
|
||
which includes a walkthrough using MAT beginning at about <a href=
|
||
"http://www.youtube.com/watch?v=_CruQY55HOk&feature=player_detailpage#t=1270">21:10</a>.
|
||
Also refer to the <a href="http://wiki.eclipse.org/index.php/MemoryAnalyzer">Eclipse Memory
|
||
Analyzer documentation</a>.</p>
|
||
|
||
<h4 id="MatCompare">Comparing heap dumps</h4>
|
||
|
||
<p>You may find it useful to compare your app's heap state at two different points in time in order
|
||
to inspect the changes in memory allocation. To compare two heap dumps using MAT:</p>
|
||
|
||
<ol>
|
||
<li>Create two HPROF files as described above, in <a href="#HeapDump">Capturing a Heap Dump</a>.
|
||
<li>Open the first HPROF file in MAT (<strong>File</strong> > <strong>Open Heap Dump</strong>).
|
||
<li>In the Navigation History view (if not visible, select <strong>Window</strong> >
|
||
<strong>Navigation History</strong>), right-click on <strong>Histogram</strong> and select
|
||
<strong>Add to Compare Basket</strong>.
|
||
<li>Open the second HPROF file and repeat steps 2 and 3.
|
||
<li>Switch to the <em>Compare Basket</em> view and click <strong>Compare the Results</strong>
|
||
(the red "!" icon in the top-right corner of the view).
|
||
</ol>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<h2 id="TriggerLeaks">Triggering Memory Leaks</h2>
|
||
|
||
<p>While using the tools described above, you should aggressively stress your app code and try
|
||
forcing memory leaks. One way to provoke memory leaks in your app is to let it
|
||
run for a while before inspecting the heap. Leaks will trickle up to the top of the allocations in
|
||
the heap. However, the smaller the leak, the longer you need to run the app in order to see it.</p>
|
||
|
||
<p>You can also trigger a memory leak in one of the following ways:</p>
|
||
<ol>
|
||
<li>Rotate the device from portrait to landscape and back again multiple times while in different
|
||
activity states. Rotating the device can often cause an app to leak an {@link android.app.Activity},
|
||
{@link android.content.Context}, or {@link android.view.View} object because the system
|
||
recreates the {@link android.app.Activity} and if your app holds a reference
|
||
to one of those objects somewhere else, the system can't garbage collect it.</li>
|
||
<li>Switch between your app and another app while in different activity states (navigate to
|
||
the Home screen, then return to your app).</li>
|
||
</ol>
|
||
|
||
<p class="note"><strong>Tip:</strong> You can also perform the above steps by using the "monkey"
|
||
test framework. For more information on running the monkey test framework, read the <a href=
|
||
"{@docRoot}tools/help/monkeyrunner_concepts.html">monkeyrunner</a>
|
||
documentation.</p> |