Merge "add docs about managing app memory" into jb-mr2-docs

This commit is contained in:
Scott Main
2013-10-14 16:49:11 +00:00
committed by Android (Google) Code Review
12 changed files with 1263 additions and 3 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 589 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 436 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 867 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 575 KiB

View File

@ -0,0 +1,494 @@
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 Androids Dalvik virtual machine performs
routine garbage collection, this doesnt 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, its 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 apps
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: &lt;GC_Reason> &lt;Amount_freed>, &lt;Heap_stats>, &lt;External_memory_stats>, &lt;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>&lt;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>&lt;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 that your app's memory is
divided between different categories, which you can do with the <code>adb meminfo</code> data.</p>
<p>When talking about how much RAM your app is using with this data, the key metrics
discussed below are:</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 apps 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 cant 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 apps 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>You can look at the memory use of your app (measured in kilobytes) with the
following adb command:</p>
<pre class="no-pretty-print">
adb shell dumpsys meminfo &lt;package_name>
</pre>
<p>For example, below is the the output for Gmails process on a tablet device. There is a lot of
information here, but key points for discussion are highlighted in different colors.</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 apps heap, composed of
your own allocations and any Zygote allocation pages that have been modified since forking your
apps 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 apps 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 cant 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>&lt;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 dont 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>&lt;sdk&gt;/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>&lt;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> &gt; <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> &gt; <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> &gt; <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&amp;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>

View File

@ -1,6 +1,18 @@
page.title=Device Monitor page.title=Device Monitor
@jd:body @jd:body
<div id="qv-wrapper">
<div id="qv">
<h2>See also</h2>
<ol>
<li><a href="{@docRoot}tools/debugging/debugging-memory.html"
>Investigating Your RAM Usage</a></li>
</ol>
</div>
</div>
<p>Android Device Monitor is a stand-alone tool that provides a graphical user interface for <p>Android Device Monitor is a stand-alone tool that provides a graphical user interface for
several Android application debugging and analysis tools. The Monitor tool does not several Android application debugging and analysis tools. The Monitor tool does not
require installation of a integrated development environment, such as Eclipse, and encapsulates the require installation of a integrated development environment, such as Eclipse, and encapsulates the
@ -14,6 +26,7 @@ following tools:</p>
<li>Pixel Perfect magnification viewer</li> <li>Pixel Perfect magnification viewer</li>
</ul> </ul>
<h2 id="usage">Usage</h2> <h2 id="usage">Usage</h2>
<p>To start Device Monitor, enter the following command from the SDK <code>tools/</code> <p>To start Device Monitor, enter the following command from the SDK <code>tools/</code>
@ -22,3 +35,7 @@ directory:</p>
<p>Start an Android emulator or connect an Android device via USB cable, and connect Device <p>Start an Android emulator or connect an Android device via USB cable, and connect Device
Monitor to the device by selecting it in the <strong>Devices</strong> window.</p> Monitor to the device by selecting it in the <strong>Devices</strong> window.</p>
<p class="note"><strong>Note:</strong> Only one debugger can be connected to your device at a time.
If you're using ADT, you may need to close the debugging tool before launching the Device Monitor
in order for the device to be fully debuggable.</p>

View File

@ -139,6 +139,7 @@
<li><a href="<?cs var:toroot ?>tools/debugging/debugging-ui.html"><span class="en">Optimizing your UI</span></a></li> <li><a href="<?cs var:toroot ?>tools/debugging/debugging-ui.html"><span class="en">Optimizing your UI</span></a></li>
<li><a href="<?cs var:toroot ?>tools/debugging/debugging-tracing.html"><span class="en">Profiling with Traceview and dmtracedump</span></a></li> <li><a href="<?cs var:toroot ?>tools/debugging/debugging-tracing.html"><span class="en">Profiling with Traceview and dmtracedump</span></a></li>
<li><a href="<?cs var:toroot ?>tools/debugging/systrace.html"><span class="en">Analysing Display and Performance with Systrace</span></a></li> <li><a href="<?cs var:toroot ?>tools/debugging/systrace.html"><span class="en">Analysing Display and Performance with Systrace</span></a></li>
<li><a href="<?cs var:toroot ?>tools/debugging/debugging-memory.html">Investigating Your RAM Usage</a></li>
<li><a href="<?cs var:toroot ?>tools/debugging/debugging-devtools.html"><span class="en">Using the Dev Tools App</span></a></li> <li><a href="<?cs var:toroot ?>tools/debugging/debugging-devtools.html"><span class="en">Using the Dev Tools App</span></a></li>
</ul> </ul>
</li> </li>

View File

@ -0,0 +1,740 @@
page.title=Managing Your App's Memory
page.tags="ram","low memory","OutOfMemoryError","onTrimMemory"
page.article=true
@jd:body
<div id="tb-wrapper">
<div id="tb">
<h2>In this document</h2>
<ol class="nolist">
<li><a href="#Android">How Android Manages Memory</a>
<ol>
<li><a href="#SharingRAM">Sharing Memory</a></li>
<li><a href="#AllocatingRAM">Allocating and Reclaiming App Memory</a></li>
<li><a href="#RestrictingMemory">Restricting App Memory</a></li>
<li><a href="#SwitchingApps">Switching Apps</a></li>
</ol>
</li>
<li><a href="#YourApp">How Your App Should Manage Memory</a>
<ol>
<li><a href="#Services">Use services sparingly</a></li>
<li><a href="#ReleaseMemoryAsUiGone">Release memory when your user interface becomes hidden</a></li>
<li><a href="#ReleaseMemoryAsTight">Release memory as memory becomes tight</a></li>
<li><a href="#CheckHowMuchMemory">Check how much memory you should use</a></li>
<li><a href="#Bitmaps">Avoid wasting memory with bitmaps</a></li>
<li><a href="#DataContainers">Use optimized data containers</a></li>
<li><a href="#Overhead">Be aware of memory overhead</a></li>
<li><a href="#Abstractions">Be careful with code abstractions</a></li>
<li><a href="#NanoProto">Use nano protobufs for serialized data</a></li>
<li><a href="#DependencyInjection">Avoid dependency injection frameworks</a></li>
<li><a href="#ExternalLibs">Be careful about using external libraries</a></li>
<li><a href="#OverallPerf">Optimize overall performance</a></li>
<li><a href="#Proguard">Use ProGuard to strip out any unneeded code</a></li>
<li><a href="#Zipalign">Use zipalign on your final APK</a></li>
<li><a href="#AnalyzeRam">Analyze your RAM usage</a></li>
<li><a href="#MultipleProcesses">Use multiple processes</a></li>
</ol>
</li>
</ol>
<h2>See Also</h2>
<ul>
<li><a href="{@docRoot}tools/debugging/debugging-memory.html">Investigating Your RAM Usage</a>
</li>
</ul>
</div>
</div>
<p>Random-access memory (RAM) is a valuable resource in any software development environment, but
it's even more valuable on a mobile operating system where physical memory is often constrained.
Although Android's Dalvik virtual machine performs routine garbage collection, this doesn't allow
you to ignore when and where your app allocates and releases memory.</p>
<p>In order for the garbage collector to reclaim memory from your app, you need to avoid
introducing memory leaks (usually caused by holding onto object references in global members) and
release any {@link java.lang.ref.Reference} objects at the appropriate time (as defined by
lifecycle callbacks discussed further below). For most apps, the Dalvik garbage collector takes
care of the rest: the system reclaims your memory allocations when the corresponding objects leave
the scope of your app's active threads.</p>
<p>This document explains how Android manages app processes and memory allocation, and how you can
proactively reduce memory usage while developing for Android. For more information about general
practices to clean up your resources when programming in Java, refer to other books or online
documentation about managing resource references. If youre looking for information about how to
analyze your apps memory once youve already built it, read <a
href="{@docRoot}tools/debugging/debugging-memory.html">Investigating Your RAM Usage</a>.</p>
<h2 id="Android">How Android Manages Memory</h2>
<p>Android does not offer swap space for memory, but it does use <a href=
"http://en.wikipedia.org/wiki/Paging" class="external-link">paging</a> and <a href=
"http://en.wikipedia.org/wiki/Memory-mapped_files" class="external-link">memory-mapping</a>
(mmapping) to manage memory. This means that any memory you modify&mdash;whether by allocating
new objects or touching mmapped pages&mdash;remains resident in RAM and cannot be paged out.
So the only way to completely release memory from your app is to release object references you may
be holding, making the memory available to the garbage collector. That is with one exception:
any files mmapped in without modification, such as code, can be paged out of RAM if the system
wants to use that memory elsewhere.</p>
<h3 id="SharingRAM">Sharing Memory</h3>
<p>In order to fit everything it needs in RAM, Android tries to share RAM pages across processes. It
can do so in the following ways:</p>
<ul>
<li>Each app process is forked from an existing process called Zygote.
The Zygote process starts when the system boots and loads common framework code and resources
(such as activity themes). To start a new app process, the system forks the Zygote process then
loads and runs the app's code in the new process. This allows most of the RAM pages allocated for
framework code and resources to be shared across all app processes.</li>
<li>Most static data is mmapped into a process. This not only allows that same data to be shared
between processes but also allows it to be paged out when needed. Example static data include:
Dalvik code (by placing it in a pre-linked {@code .odex} file for direct mmapping), app resources
(by designing the resource table to be a structure that can be mmapped and by aligning the zip
entries of the APK), and traditional project elements like native code in {@code .so} files.</li>
<li>In many places, Android shares the same dynamic RAM across processes using explicitly allocated
shared memory regions (either with ashmem or gralloc). For example, window surfaces use shared
memory between the app and screen compositor, and cursor buffers use shared memory between the
content provider and client.</li>
</ul>
<p>Due to the extensive use of shared memory, determining how much memory your app is using requires
care. Techniques to properly determine your app's memory use are discussed in <a
href="{@docRoot}tools/debugging/debugging-memory.html">Investigating Your RAM Usage</a>.</p>
<h3 id="AllocatingRAM">Allocating and Reclaiming App Memory</h3>
<p>Here are some facts about how Android allocates then reclaims memory from your app:</p>
<ul>
<li>The Dalvik heap for each process is constrained to a single virtual memory range. This defines
the logical heap size, which can grow as it needs to (but only up to a limit that the system defines
for each app).</li>
<li>The logical size of the heap is not the same as the amount of physical memory used by the heap.
When inspecting your app's heap, Android computes a value called the Proportional Set Size (PSS),
which accounts for both dirty and clean pages that are shared with other processes&mdash;but only in an
amount that's proportional to how many apps share that RAM. This (PSS) total is what the system
considers to be your physical memory footprint. For more information about PSS, see the <a
href="{@docRoot}tools/debugging/debugging-memory.html#ViewingAllocations">Investigating Your
RAM Usage</a> guide.</li>
<li>The Dalvik heap does not compact the logical size of the heap, meaning that Android does not
defragment the heap to close up space. Android can only shrink the logical heap size when there
is unused space at the end of the heap. But this doesn't mean the physical memory used by the heap
can't shrink. After garbage collection, Dalvik walks the heap and finds unused pages, then returns
those pages to the kernel using madvise. So, paired allocations and deallocations of large
chunks should result in reclaiming all (or nearly all) the physical memory used. However,
reclaiming memory from small allocations can be much less efficient because the page used
for a small allocation may still be shared with something else that has not yet been freed.</li>
</ul>
<h3 id="RestrictingMemory">Restricting App Memory</h3>
<p>To maintain a functional multi-tasking environment, Android sets a hard limit on the heap size
for each app. The exact heap size limit varies between devices based on how much RAM the device
has available overall. If your app has reached the heap capacity and tries to allocate more
memory, it will receive an {@link java.lang.OutOfMemoryError}.</p>
<p>In some cases, you might want to query the system to determine exactly how much heap space you
have available on the current device&mdash;for example, to determine how much data is safe to keep in a
cache. You can query the system for this figure by calling {@link
android.app.ActivityManager#getMemoryClass()}. This returns an integer indicating the number of
megabytes available for your app's heap. This is discussed further below, under
<a href="#CheckHowMuchMemory">Check how much memory you should use</a>.</p>
<h3 id="SwitchingApps">Switching Apps</h3>
<p>Instead of using swap space when the user switches between apps, Android keeps processes that
are not hosting a foreground ("user visible") app component in a least-recently used (LRU) cache.
For example, when the user first launches an app, a process is created for it, but when the user
leaves the app, that process does <em>not</em> quit. The system keeps the process cached, so if
the user later returns to the app, the process is reused for faster app switching.</p>
<p>If your app has a cached process and it retains memory that it currently does not need,
then your app&mdash;even while the user is not using it&mdash;is constraining the system's
overall performance. So, as the system runs low on memory, it may kill processes in the LRU cache
beginning with the process least recently used, but also giving some consideration toward
which processes are most memory intensive. To keep your process cached as long as possible, follow
the advice in the following sections about when to release your references.</p>
<p>More information about how processes are cached while not running in the foreground and how
Android decides which ones
can be killed is available in the <a href="{@docRoot}guide/components/processes-and-threads.html"
>Processes and Threads</a> guide.</p>
<h2 id="YourApp">How Your App Should Manage Memory</h2>
<p>You should consider RAM constraints throughout all phases of development, including during app
design (before you begin development). There are many
ways you can design and write code that lead to more efficient results, through aggregation of the
same techniques applied over and over.</p>
<p>You should apply the following techniques while designing and implementing your app to make it
more memory efficient.</p>
<h3 id="Services">Use services sparingly</h3>
<p>If your app needs a <a href="{@docRoot}guide/components/services.html">service</a>
to perform work in the background, do not keep it running unless
it's actively performing a job. Also be careful to never leak your service by failing to stop it
when its work is done.</p>
<p>When you start a service, the system prefers to always keep the process for that service
running. This makes the process very expensive because the RAM used by the service cant be used by
anything else or paged out. This reduces the number of cached processes that the system can keep in
the LRU cache, making app switching less efficient. It can even lead to thrashing in the system
when memory is tight and the system cant maintain enough processes to host all the services
currently running.</p>
<p>The best way to limit the lifespan of your service is to use an {@link
android.app.IntentService}, which finishes
itself as soon as it's done handling the intent that started it. For more information, read
<a href="{@docRoot}training/run-background-service/index.html">Running in a Background Service</a>
.</p>
<p>Leaving a service running when its not needed is <strong>one of the worst memory-management
mistakes</strong> an Android app can make. So dont be greedy by keeping a service for your app
running. Not only will it increase the risk of your app performing poorly due to RAM constraints,
but users will discover such misbehaving apps and uninstall them.</p>
<h3 id="ReleaseMemoryAsUiGone">Release memory when your user interface becomes hidden</h3>
<p>When the user navigates to a different app and your UI is no longer visible, you should
release any resources that are used by only your UI. Releasing UI resources at this time can
significantly increase the system's capacity for cached processes, which has a direct impact on the
quality of the user experience.</p>
<p>To be notified when the user exits your UI, implement the {@link
android.content.ComponentCallbacks2#onTrimMemory onTrimMemory()} callback in your {@link
android.app.Activity} classes. You should use this
method to listen for the {@link android.content.ComponentCallbacks2#TRIM_MEMORY_UI_HIDDEN} level,
which indicates your UI is now hidden from view and you should free resources that only your UI
uses.</p>
<p>Notice that your app receives the {@link android.content.ComponentCallbacks2#onTrimMemory
onTrimMemory()} callback with {@link android.content.ComponentCallbacks2#TRIM_MEMORY_UI_HIDDEN}
only when <em>all the UI components</em> of your app process become hidden from the user.
This is distinct
from the {@link android.app.Activity#onStop onStop()} callback, which is called when an {@link
android.app.Activity} instance becomes hidden, which occurs even when the user moves to
another activity in your app. So although you should implement {@link android.app.Activity#onStop
onStop()} to release activity resources such as a network connection or to unregister broadcast
receivers, you usually should not release your UI resources until you receive {@link
android.content.ComponentCallbacks2#onTrimMemory onTrimMemory(TRIM_MEMORY_UI_HIDDEN)}. This ensures
that if the user navigates <em>back</em> from another activity in your app, your UI resources are
still available to resume the activity quickly.</p>
<h3 id="ReleaseMemoryAsTight">Release memory as memory becomes tight</h3>
<p>During any stage of your app's lifecycle, the {@link
android.content.ComponentCallbacks2#onTrimMemory onTrimMemory()} callback also tells you when
the overall device memory is getting low. You should respond by further releasing resources based
on the following memory levels delivered by {@link android.content.ComponentCallbacks2#onTrimMemory
onTrimMemory()}:</p>
<ul>
<li>{@link android.content.ComponentCallbacks2#TRIM_MEMORY_RUNNING_MODERATE}
<p>Your app is running and not considered killable, but the device is running low on memory and the
system is actively killing processes in the LRU cache.</p>
</li>
<li>{@link android.content.ComponentCallbacks2#TRIM_MEMORY_RUNNING_LOW}
<p>Your app is running and not considered killable, but the device is running much lower on
memory so you should release unused resources to improve system performance (which directly
impacts your app's performance).</p>
</li>
<li>{@link android.content.ComponentCallbacks2#TRIM_MEMORY_RUNNING_CRITICAL}
<p>Your app is still running, but the system has already killed most of the processes in the
LRU cache, so you should release all non-critical resources now. If the system cannot reclaim
sufficient amounts of RAM, it will clear all of the LRU cache and begin killing processes that
the system prefers to keep alive, such as those hosting a running service.</p>
</li>
</ul>
<p>Also, when your app process is currently cached, you may receive one of the following
levels from {@link android.content.ComponentCallbacks2#onTrimMemory onTrimMemory()}:</p>
<ul>
<li>{@link android.content.ComponentCallbacks2#TRIM_MEMORY_BACKGROUND}
<p>The system is running low on memory and your process is near the beginning of the LRU list.
Although your app process is not at a high risk of being killed, the system may already be killing
processes in the LRU cache. You should release resources that are easy to recover so your process
will remain in the list and resume quickly when the user returns to your app.</p>
</li>
<li>{@link android.content.ComponentCallbacks2#TRIM_MEMORY_MODERATE}
<p>The system is running low on memory and your process is near the middle of the LRU list. If the
system becomes further constrained for memory, there's a chance your process will be killed.</p>
</li>
<li>{@link android.content.ComponentCallbacks2#TRIM_MEMORY_COMPLETE}
<p>The system is running low on memory and your process is one of the first to be killed if the
system does not recover memory now. You should release everything that's not critical to
resuming your app state.</p>
</li>
</ul>
<p>Because the {@link android.content.ComponentCallbacks2#onTrimMemory onTrimMemory()} callback was
added in API level 14, you can use the {@link android.content.ComponentCallbacks#onLowMemory()}
callback as a fallback for older versions, which is roughly equivalent to the {@link
android.content.ComponentCallbacks2#TRIM_MEMORY_COMPLETE} event.</p>
<p class="note"><strong>Note:</strong> When the system begins killing processes in the LRU cache,
although it primarily works bottom-up, it does give some consideration to which processes are
consuming more memory and will thus provide the system more memory gain if killed.
So the less memory you consume while in the LRU list overall, the better your chances are
to remain in the list and be able to quickly resume.</p>
<h3 id="CheckHowMuchMemory">Check how much memory you should use</h3>
<p>As mentioned earlier, each Android-powered device has a different amount of RAM available to the
system and thus provides a different heap limit for each app. You can call {@link
android.app.ActivityManager#getMemoryClass()} to get an estimate of your app's available heap in
megabytes. If your app tries to allocate more memory than is available here, it will receive an
{@link java.lang.OutOfMemoryError}.</p>
<p>In very special situations, you can request a larger heap size by setting the <a
href="{@docRoot}guide/topics/manifest/application-element.html#largeHeap">{@code largeHeap}</a>
attribute to "true" in the manifest <a
href="{@docRoot}guide/topics/manifest/application-element.html">{@code &lt;application&gt;}</a>
tag. If you do so, you can call {@link
android.app.ActivityManager#getLargeMemoryClass()} to get an estimate of the large heap size.</p>
<p>However, the ability to request a large heap is intended only for a small set of apps that can
justify the need to consume more RAM (such as a large photo editing app). <strong>Never request a
large heap simply because you've run out of memory</strong> and you need a quick fix&mdash;you
should use it only when you know exactly where all your memory is being allocated and why it must
be retained. Yet, even when you're confident your app can justify the large heap, you should avoid
requesting it to whatever extent possible. Using the extra memory will increasingly be to the
detriment of the overall user experience because garbage collection will take longer and system
performance may be slower when task switching or performing other common operations.</p>
<p>Additionally, the large heap size is not the same on all devices and, when running on
devices that have limited RAM, the large heap size may be exactly the same as the regular heap
size. So even if you do request the large heap size, you should call {@link
android.app.ActivityManager#getMemoryClass()} to check the regular heap size and strive to always
stay below that limit.</p>
<h3 id="Bitmaps">Avoid wasting memory with bitmaps</h3>
<p>When you load a bitmap, keep it in RAM only at the resolution you need for the current device's
screen, scaling it down if the original bitmap is a higher resolution. Keep in mind that an
increase in bitmap resolution results in a corresponding (increase<sup>2</sup>) in memory needed,
because both the X and Y dimensions increase.</p>
<p class="note"><strong>Note:</strong> On Android 2.3.x (API level 10) and below, bitmap objects
always appear as the same size in your app heap regardless of the image resolution (the actual
pixel data is stored separately in native memory). This makes it more difficult to debug the bitmap
memory allocation because most heap analysis tools do not see the native allocation. However,
beginning in Android 3.0 (API level 11), the bitmap pixel data is allocated in your app's Dalvik
heap, improving garbage collection and debuggability. So if your app uses bitmaps and you're having
trouble discovering why your app is using some memory on an older device, switch to a device
running Android 3.0 or higher to debug it.</p>
<p>For more tips about working with bitmaps, read <a
href="{@docRoot}training/displaying-bitmaps/manage-memory.html">Managing Bitmap Memory</a>.</p>
<h3 id="DataContainers">Use optimized data containers</h3>
<p>Take advantage of optimized containers in the Android framework, such as {@link
android.util.SparseArray}, {@link android.util.SparseBooleanArray}, and {@link
android.support.v4.util.LongSparseArray}. The generic {@link java.util.HashMap}
implementation can be quite memory
inefficient because it needs a separate entry object for every mapping. Additionally, the {@link
android.util.SparseArray} classes are more efficient because they avoid the system's need
to <acronym title=
"Automatic conversion from primitive types to object classes (such as int to Integer)"
>autobox</acronym>
the key and sometimes value (which creates yet another object or two per entry). And don't be
afraid of dropping down to raw arrays when that makes sense.</p>
<h3 id="Overhead">Be aware of memory overhead</h3>
<p>Be knowledgeable about the cost and overhead of the language and libraries you are using, and
keep this information in mind when you design your app, from start to finish. Often, things on the
surface that look innocuous may in fact have a large amount of overhead. Examples include:</p>
<ul>
<li>Enums often require more than twice as much memory as static constants. You should strictly
avoid using enums on Android.</li>
<li>Every class in Java (including anonymous inner classes) uses about 500 bytes of code.</li>
<li>Every class instance has 12-16 bytes of RAM overhead.</li>
<li>Putting a single entry into a {@link java.util.HashMap} requires the allocation of an
additional entry object that takes 32 bytes (see the previous section about <a
href="#DataContainers">optimized data containers</a>).</li>
</ul>
<p>A few bytes here and there quickly add up—app designs that are class- or object-heavy will suffer
from this overhead. That can leave you in the difficult position of looking at a heap analysis and
realizing your problem is a lot of small objects using up your RAM.</p>
<h3 id="Abstractions">Be careful with code abstractions</h3>
<p>Often, developers use abstractions simply as a "good programming practice," because abstractions
can improve code flexibility and maintenance. However, abstractions come at a significant cost:
generally they require a fair amount more code that needs to be executed, requiring more time and
more RAM for that code to be mapped into memory. So if your abstractions aren't supplying a
significant benefit, you should avoid them.</p>
<h3 id="NanoProto">Use nano protobufs for serialized data</h3>
<p><a href="https://developers.google.com/protocol-buffers/docs/overview">Protocol
buffers</a> are a language-neutral, platform-neutral, extensible mechanism designed by Google for
serializing structured data&mdash;think XML, but smaller, faster, and simpler. If you decide to use
protobufs for your data, you should always use nano protobufs in your client-side code. Regular
protobufs generate extremely verbose code, which will cause many kinds of problems in your app:
increased RAM use, significant APK size increase, slower execution, and quickly hitting the DEX
symbol limit.</p>
<p>For more information, see the "Nano version" section in the <a
href="https://android.googlesource.com/platform/external/protobuf/+/master/java/README.txt"
class="external-link">protobuf readme</a>.</p>
<h3 id="DependencyInjection">Avoid dependency injection frameworks</h3>
<p>Using a dependency injection framework such as <a
href="https://code.google.com/p/google-guice/" class="external-link">Guice</a> or
<a href="https://github.com/roboguice/roboguice" class="external-link">RoboGuice</a> may be
attractive because they can simplify the code you write and provide an adaptive environment
that's useful for testing and other configuration changes. However, these frameworks tend to perform
a lot of process initialization by scanning your code for annotations, which can require significant
amounts of your code to be mapped into RAM even though you don't need it. These mapped pages are
allocated into clean memory so Android can drop them, but that won't happen until the pages have
been left in memory for a long period of time.</p>
<h3 id="ExternalLibs">Be careful about using external libraries</h3>
<p>External library code is often not written for mobile environments and can be inefficient when used
for work on a mobile client. At the very least, when you decide to use an external library, you
should assume you are taking on a significant porting and maintenance burden to optimize the
library for mobile. Plan for that work up-front and analyze the library in terms of code size and
RAM footprint before deciding to use it at all.</p>
<p>Even libraries supposedly designed for use on Android are potentially dangerous because each
library may do things differently. For example, one library may use nano protobufs while another
uses micro protobufs. Now you have two different protobuf implementations in your app. This can and
will also happen with different implementations of logging, analytics, image loading frameworks,
caching, and all kinds of other things you don't expect. <a
href="{@docRoot}tools/help/proguard.html">ProGuard</a> won't save you here because these
will all be lower-level dependencies that are required by the features for which you want the
library. This becomes especially problematic when you use an {@link android.app.Activity}
subclass from a library (which
will tend to have wide swaths of dependencies), when libraries use reflection (which is common and
means you need to spend a lot of time manually tweaking ProGuard to get it to work), and so on.</p>
<p>Also be careful not to fall into the trap of using a shared library for one or two features out of
dozens of other things it does; you don't want to pull in a large amount of code and overhead that
you don't even use. At the end of the day, if there isn't an existing implementation that is a
strong match for what you need to do, it may be best if you create your own implementation.</p>
<h3 id="OverallPerf">Optimize overall performance</h3>
<p>A variety of information about optimizing your app's overall performance is available
in other documents listed in <a href="{@docRoot}training/best-performance.html">Best Practices
for Performance</a>. Many of these documents include optimizations tips for CPU performance, but
many of these tips also help optimize your app's memory use, such as by reducing the number of
layout objects required by your UI.</p>
<p>You should also read about <a href="{@docRoot}tools/debugging/debugging-ui.html">optimizing
your UI</a> with the layout debugging tools and take advantage of
the optimization suggestions provided by the <a
href="{@docRoot}tools/debugging/improving-w-lint.html">lint tool</a>.</p>
<h3 id="Proguard">Use ProGuard to strip out any unneeded code</h3>
<p>The <a href="{@docRoot}tools/help/proguard.html">ProGuard</a> tool shrinks,
optimizes, and obfuscates your code by removing unused code and renaming classes, fields, and
methods with semantically obscure names. Using ProGuard can make your code more compact, requiring
fewer RAM pages to be mapped.</p>
<h3 id="Zipalign">Use zipalign on your final APK</h3>
<p>If you do any post-processing of an APK generated by a build system (including signing it
with your final production certificate), then you must run <a
href="{@docRoot}tools/help/zipalign.html">zipalign</a> on it to have it re-aligned.
Failing to do so can cause your app to require significantly more RAM, because things like
resources can no longer be mmapped from the APK.</p>
<p class="note"><strong>Note:</strong> Google Play Store does not accept APK files that
are not zipaligned.</p>
<h3 id="AnalyzeRam">Analyze your RAM usage</h3>
<p>Once you achieve a relatively stable build, begin analyzing how much RAM your app is using
throughout all stages of its lifecycle. For information about how to analyze your app, read <a
href="{@docRoot}tools/debugging/debugging-memory.html">Investigating Your RAM Usage</a>.</p>
<h3 id="MultipleProcesses">Use multiple processes</h3>
<p>If it's appropriate for your app, an advanced technique that may help you manage your app's
memory is dividing components of your app into multiple processes. This technique must always be
used carefully and <strong>most apps should not run multiple processes</strong>, as it can easily
increase&mdash;rather than decrease&mdash;your RAM footprint if done incorrectly. It is primarily
useful to apps that may run significant work in the background as well as the foreground and can
manage those operations separately.</p>
<p>An example of when multiple processes may be appropriate is when building a music player that
plays music from a service for long period of time. If
the entire app runs in one process, then many of the allocations performed for its activity UI must
be kept around as long as it is playing music, even if the user is currently in another app and the
service is controlling the playback. An app like this may be split into two process: one for its
UI, and the other for the work that continues running in the background service.</p>
<p>You can specify a separate process for each app component by declaring the <a href=
"{@docRoot}guide/topics/manifest/service-element.html#proc">{@code android:process}</a> attribute
for each component in the manifest file. For example, you can specify that your service should run
in a process separate from your app's main process by declaring a new process named "background"
(but you can name the process anything you like):</p>
<pre>
&lt;service android:name=".PlaybackService"
android:process=":background" />
</pre>
<p>Your process name should begin with a colon (':') to ensure that the process remains private to
your app.</p>
<p>Before you decide to create a new process, you need to understand the memory implications.
To illustrate the consequences of each process, consider that an empty process doing basically
nothing has an extra memory footprint of about 1.4MB, as shown by the memory information
dump below.</p>
<pre class="no-pretty-print">
adb shell dumpsys meminfo com.example.android.apis:empty
** MEMINFO in pid 10172 [com.example.android.apis:empty] **
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 1864 1800 63
Dalvik Heap 764 0 5228 316 0 0 5584 5499 85
Dalvik Other 619 0 3784 448 0 0
Stack 28 0 8 28 0 0
Other dev 4 0 12 0 0 4
.so mmap 287 0 2840 212 972 0
.apk mmap 54 0 0 0 136 0
.dex mmap 250 148 0 0 3704 148
Other mmap 8 0 8 8 20 0
Unknown 403 0 600 380 0 0
TOTAL 2417 148 12480 1392 4832 152 7448 7299 148
</pre>
<p class="note"><strong>Note:</strong> More information about how to read this output is provided
in <a href="{@docRoot}tools/debugging/debugging-memory.html#ViewingAllocations">Investigating
Your RAM Usage</a>. The key data here is the <em>Private Dirty</em> and <em>Private
Clean</em> memory, which shows that this process is using almost 1.4MB of non-pageable RAM
(distributed across the Dalvik heap, native allocations, book-keeping, and library-loading),
and another 150K of RAM for code that has been mapped in to execute.</p>
<p>This memory footprint for an empty process is fairly significant and it can quickly
grow as you start doing work in that process. For
example, here is the memory use of a process that is created only to show an activity with some
text in it:</p>
<pre class="no-pretty-print">
** MEMINFO in pid 10226 [com.example.android.helloactivity] **
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 3000 2951 48
Dalvik Heap 1074 0 4928 776 0 0 5744 5658 86
Dalvik Other 802 0 3612 664 0 0
Stack 28 0 8 28 0 0
Ashmem 6 0 16 0 0 0
Other dev 108 0 24 104 0 4
.so mmap 2166 0 2824 1828 3756 0
.apk mmap 48 0 0 0 632 0
.ttf mmap 3 0 0 0 24 0
.dex mmap 292 4 0 0 5672 4
Other mmap 10 0 8 8 68 0
Unknown 632 0 412 624 0 0
TOTAL 5169 4 11832 4032 10152 8 8744 8609 134
</pre>
<p>The process has now almost tripled in size, to 4MB, simply by showing some text in the UI. This
leads to an important conclusion: If you are going to split your app into multiple processes, only
one process should be responsible for UI. Other processes should avoid any UI, as this will quickly
increase the RAM required by the process (especially once you start loading bitmap assets and other
resources). It may then be hard or impossible to reduce the memory usage once the UI is drawn.</p>
<p>Additionally, when running more than one process, it's more important than ever that you keep your
code as lean as possible, because any unnecessary RAM overhead for common implementations are now
replicated in each process. For example, if you are using enums (though <a
href="#Overhead">you should not use enums</a>), all of
the RAM needed to create and initialize those constants is duplicated in each process, and any
abstractions you have with adapters and temporaries or other overhead will likewise be replicated.</p>
<p>Another concern with multiple processes is the dependencies that exist between them. For example,
if your app has a content provider that you have running in the default process which also hosts
your UI, then code in a background process that uses that content provider will also require that
your UI process remain in RAM. If your goal is to have a background process that can run
independently of a heavy-weight UI process, it can't have dependencies on content providers or
services that execute in the UI process.</p>
<!-- THE FOLLOWING IS OVERWHELMING AND NOT NECESSARY FOR MOST APPS, LEAVING OUT FOR NOW
<p>You can examine the dependencies between your processes with the command:</p>
<pre class="no-pretty-print">
adb shell dumpsys activity
</pre>
<p>This dumps various information about the Activity Manager's state, ending with a list of all
processes in their memory management order, including the reason each process is at its given
level. For example, below is a dump with the Music app in the foreground.</p>
<pre class="no-pretty-print">
ACTIVITY MANAGER RUNNING PROCESSES (dumpsys activity processes)
Process LRU list (sorted by oom_adj):
PERS # 4: adj=sys /F trm= 0 20674:system/1000 (fixed)
PERS #39: adj=pers /F trm= 0 20964:com.android.nfc/1027 (fixed)
PERS # 2: adj=pers /F trm= 0 20959:com.android.phone/1001 (fixed)
PERS # 1: adj=pers /F trm= 0 20779:com.android.systemui/u0a10057 (fixed)
Proc #11: adj=fore /FA trm= 0 8663:com.google.android.music:ui/u0a10043 (top-activity)
Proc #10: adj=fore /F trm= 0 30881:com.google.android.music:main/u0a10043 (provider)
com.google.android.music/.store.MusicContentProvider<=Proc{8663:com.google.android.music:ui/u0a10043}
Proc # 6: adj=fore /F trm= 0 21014:com.google.process.gapps/u0a10023 (provider)
com.google.android.gsf/.settings.GoogleSettingsProvider<=Proc{20935:com.google.process.location/u0a10023}
Proc #38: adj=vis /F trm= 0 21028:com.android.nfc:handover/1027 (service)
com.android.nfc/.handover.HandoverService<=Proc{20964:com.android.nfc/1027}
Proc # 7: adj=vis /B trm= 0 20935:com.google.process.location/u0a10023 (service)
com.google.android.location/.GeocodeService<=Proc{20674:system/1000}
Proc # 3: adj=vis /F trm= 0 21225:com.android.bluetooth/1002 (service)
com.android.bluetooth/.hfp.HeadsetService<=Proc{20674:system/1000}
Proc # 0: adj=vis /F trm= 0 20908:com.google.android.inputmethod.latin/u0a10035 (service)
com.google.android.inputmethod.latin/com.android.inputmethod.latin.LatinIME<=Proc{20674:system/1000}
Proc #34: adj=svc /B trm= 0 16765:com.google.android.apps.currents/u0a10012 (started-services)
Proc #14: adj=svc /B trm= 0 21148:com.google.android.gms/u0a10023 (started-services)
Proc #12: adj=home /B trm= 0 20989:com.android.launcher/u0a10036 (home)
Proc #37: adj=svcb /B trm= 0 15194:com.google.android.apps.googlevoice/u0a10089 (started-services)
Proc #17: adj=svcb /B trm= 0 24537:android.process.media/u0a10016 (started-services)
Proc #35: adj=bak /B trm= 0 16087:com.android.defcontainer/u0a10013 (service)
com.android.defcontainer/.DefaultContainerService<=Proc{16050:com.android.settings/1000}
Proc #16: adj=bak /B trm= 0 7334:com.google.android.gm/u0a10022 (bg-act)
Proc #15: adj=bak /B trm= 0 22499:com.google.android.googlequicksearchbox/u0a10060 (bg-act)
Proc # 9: adj=bak /B trm= 0 20856:com.google.android.gsf.login/u0a10023 (bg-empty)
Proc #26: adj=bak+1/B trm= 0 9923:com.android.mms/u0a10042 (bg-act)
Proc #23: adj=bak+1/B trm= 0 16721:com.android.chrome/u0a10010 (bg-act)
Proc #22: adj=bak+1/B trm= 0 17596:com.android.chrome:sandboxed_process0/u0a10010i33 (service)
com.android.chrome/org.chromium.content.app.SandboxedProcessService0<=Proc{16721:com.android.chrome/u0a10010}
Proc #19: adj=bak+1/B trm= 0 17442:com.google.android.youtube/u0a10067 (bg-services)
Proc #18: adj=bak+2/B trm= 0 16740:com.google.android.apps.plus/u0a10052 (bg-empty)
Proc #13: adj=bak+2/B trm= 0 7707:com.android.musicfx/u0a10044 (bg-empty)
Proc #36: adj=bak+3/B trm= 0 16050:com.android.settings/1000 (bg-act)
Proc #33: adj=bak+3/B trm= 0 16863:com.android.dialer/u0a10015 (bg-act)
</pre>
<p class="note"><strong>Note:</strong> The exact details of what is shown here will vary across
platform versions as process management policies are tweaked and improved.</p>
<p>Details on the highlighted sections are:</p>
<ol>
<li>Foreground app: This is the current app running in the foreground -- it is in the "fore" memory
class because it is the top activity on the activity stack.</li>
<li>Persistent processes: These are processes that are part of the core system that must always be
running.</li>
<li>Dependent process: This shows how the Music app is using two processes. Its UI process has a
dependency on the "main" process (through a content provider). So while the UI process is in use,
the main process must also be kept around. This means the app's memory footprint is actually the
sum of both processes. You will have this kind of connection on a content provider any time you
have active calls into it or have unclosed cursors or file streams that came from it.</li>
<li>Visible processes: These are processes that count in some way as "visible" to the user. This
generally means that it is either something the user can literally see (such as a process hosting a
paused but visible activity that is behind a non-full-screen dialog) or is something the user might
notice if the process disappeared (such as a foreground service playing music). You should be
certain that any process you have running at the "visible" level is indeed critical to the user,
because they are very expensive to the overall RAM load.</li>
<li>Service processes: These are processes running long-term jobs in a service. This level of the
list is the start of less-critical processes, which the system has some freedom to kill if RAM is
needed elsewhere. These services are still quite expensive because they can be killed only
temporarily and the system tries to keep them running whenever possible.</li>
<li>Home process: A special slot for the process that hosts the current Home activity, to try to
prevent it from being killed as much as possible. Killing this process is much more damaging to the
user experience than killing other cached processes, because so much user interaction goes through
home.</li>
<li>Secondary service processes: These are services that have been running for a relatively long time
and so should be killed more aggressively when RAM is needed elsewhere.</li>
<li>Cached processes: These are cached processes held in the LRU cache, which allow for fast app
switching and component launching. These processes are not required and the system will kill them
as needed to reclaim memory. You will often see a process hosting a running service here—this is
part of a platform policy of allowing very long-running services to drop down into the LRU list and
eventually be killed. If the service should continue running (as defined by the {@link
android.app.Service#onStartCommand onStartCommand()} return value, such as {@link
android.app.Service#START_STICKY}), the the system eventually restarts it. This avoids issues with
such services having memory leaks that over time reduce the number of regular cached processes that
can be kept.</li>
</ol>
<p>This numbered list of processes is essentially the LRU list of processes that the framework
provides to the kernel to help it determine which processes it should kill as it needs more RAM.
The kernel's out of memory killer will generally begin from the bottom of this list, killing the
last process and working its way up. It may not do it in exactly this order, as it can also take
into consideration other factors such as the relative RAM footprint of processes to some degree.</p>
<p>There are many other options you can use with the activity command to analyze further details of
your app's state&mdash;use <code>adb shell dumpsys activity -h</code> for help on its use.</p>
-->

View File

@ -8,7 +8,7 @@ page.article=true
<div id="tb"> <div id="tb">
<h2>In this document</h2> <h2>In this document</h2>
<ol> <ol class="nolist">
<li><a href="#anr">What Triggers ANR?</a></li> <li><a href="#anr">What Triggers ANR?</a></li>
<li><a href="#Avoiding">How to Avoid ANRs</a></li> <li><a href="#Avoiding">How to Avoid ANRs</a></li>
<li><a href="#Reinforcing">Reinforcing Responsiveness</a></li> <li><a href="#Reinforcing">Reinforcing Responsiveness</a></li>

View File

@ -8,7 +8,7 @@ page.article=true
<div id="tb"> <div id="tb">
<h2>In this document</h2> <h2>In this document</h2>
<ol> <ol class="nolist">
<li><a href="#JavaVM_and_JNIEnv">JavaVM and JNIEnv</a></li> <li><a href="#JavaVM_and_JNIEnv">JavaVM and JNIEnv</a></li>
<li><a href="#threads">Threads</a></li> <li><a href="#threads">Threads</a></li>
<li><a href="#jclass_jmethodID_and_jfieldID">jclass, jmethodID, and jfieldID</a></li> <li><a href="#jclass_jmethodID_and_jfieldID">jclass, jmethodID, and jfieldID</a></li>

View File

@ -6,7 +6,7 @@ page.article=true
<div id="tb"> <div id="tb">
<h2>In this document</h2> <h2>In this document</h2>
<ol> <ol class="nolist">
<li><a href="#ObjectCreation">Avoid Creating Unnecessary Objects</a></li> <li><a href="#ObjectCreation">Avoid Creating Unnecessary Objects</a></li>
<li><a href="#PreferStatic">Prefer Static Over Virtual</a></li> <li><a href="#PreferStatic">Prefer Static Over Virtual</a></li>
<li><a href="#UseFinal">Use Static Final For Constants</a></li> <li><a href="#UseFinal">Use Static Final For Constants</a></li>

View File

@ -1103,6 +1103,14 @@ include the action bar on devices running Android 2.1 or higher."
</div> </div>
<ul> <ul>
<li>
<a href="<?cs var:toroot ?>training/articles/memory.html"
description=
"How to keep your app's memory footprint small in order to improve performance
on a variety of mobile devices."
>Managing Your App's Memory</a>
</li>
<li> <li>
<a href="<?cs var:toroot ?>training/articles/perf-tips.html" <a href="<?cs var:toroot ?>training/articles/perf-tips.html"
description= description=