blob: f15af689310ae475d674bbd77c1040a80b997c03 [file] [log] [blame]
Scott Maina3f0e012013-09-19 17:45:40 -07001page.title=Managing Your App's Memory
Joe Fernandez33baa5a2013-11-14 11:41:19 -08002page.tags=ram,low memory,OutOfMemoryError,onTrimMemory
Scott Maina3f0e012013-09-19 17:45:40 -07003page.article=true
4@jd:body
5
6
7<div id="tb-wrapper">
8<div id="tb">
9
10<h2>In this document</h2>
11<ol class="nolist">
12 <li><a href="#Android">How Android Manages Memory</a>
13 <ol>
14 <li><a href="#SharingRAM">Sharing Memory</a></li>
15 <li><a href="#AllocatingRAM">Allocating and Reclaiming App Memory</a></li>
16 <li><a href="#RestrictingMemory">Restricting App Memory</a></li>
17 <li><a href="#SwitchingApps">Switching Apps</a></li>
18 </ol>
19 </li>
20 <li><a href="#YourApp">How Your App Should Manage Memory</a>
21 <ol>
22 <li><a href="#Services">Use services sparingly</a></li>
23 <li><a href="#ReleaseMemoryAsUiGone">Release memory when your user interface becomes hidden</a></li>
24 <li><a href="#ReleaseMemoryAsTight">Release memory as memory becomes tight</a></li>
25 <li><a href="#CheckHowMuchMemory">Check how much memory you should use</a></li>
26 <li><a href="#Bitmaps">Avoid wasting memory with bitmaps</a></li>
27 <li><a href="#DataContainers">Use optimized data containers</a></li>
28 <li><a href="#Overhead">Be aware of memory overhead</a></li>
29 <li><a href="#Abstractions">Be careful with code abstractions</a></li>
30 <li><a href="#NanoProto">Use nano protobufs for serialized data</a></li>
31 <li><a href="#DependencyInjection">Avoid dependency injection frameworks</a></li>
32 <li><a href="#ExternalLibs">Be careful about using external libraries</a></li>
33 <li><a href="#OverallPerf">Optimize overall performance</a></li>
34 <li><a href="#Proguard">Use ProGuard to strip out any unneeded code</a></li>
35 <li><a href="#Zipalign">Use zipalign on your final APK</a></li>
36 <li><a href="#AnalyzeRam">Analyze your RAM usage</a></li>
37 <li><a href="#MultipleProcesses">Use multiple processes</a></li>
38 </ol>
39 </li>
40</ol>
41<h2>See Also</h2>
42<ul>
43 <li><a href="{@docRoot}tools/debugging/debugging-memory.html">Investigating Your RAM Usage</a>
44 </li>
45</ul>
46
47</div>
48</div>
49
50
51<p>Random-access memory (RAM) is a valuable resource in any software development environment, but
52it's even more valuable on a mobile operating system where physical memory is often constrained.
53Although Android's Dalvik virtual machine performs routine garbage collection, this doesn't allow
54you to ignore when and where your app allocates and releases memory.</p>
55
56<p>In order for the garbage collector to reclaim memory from your app, you need to avoid
57introducing memory leaks (usually caused by holding onto object references in global members) and
58release any {@link java.lang.ref.Reference} objects at the appropriate time (as defined by
59lifecycle callbacks discussed further below). For most apps, the Dalvik garbage collector takes
60care of the rest: the system reclaims your memory allocations when the corresponding objects leave
61the scope of your app's active threads.</p>
62
63<p>This document explains how Android manages app processes and memory allocation, and how you can
64proactively reduce memory usage while developing for Android. For more information about general
65practices to clean up your resources when programming in Java, refer to other books or online
66documentation about managing resource references. If you’re looking for information about how to
67analyze your app’s memory once you’ve already built it, read <a
68href="{@docRoot}tools/debugging/debugging-memory.html">Investigating Your RAM Usage</a>.</p>
69
70
71
72
73<h2 id="Android">How Android Manages Memory</h2>
74
75<p>Android does not offer swap space for memory, but it does use <a href=
76"http://en.wikipedia.org/wiki/Paging" class="external-link">paging</a> and <a href=
77"http://en.wikipedia.org/wiki/Memory-mapped_files" class="external-link">memory-mapping</a>
78(mmapping) to manage memory. This means that any memory you modify&mdash;whether by allocating
79new objects or touching mmapped pages&mdash;remains resident in RAM and cannot be paged out.
80So the only way to completely release memory from your app is to release object references you may
81be holding, making the memory available to the garbage collector. That is with one exception:
82any files mmapped in without modification, such as code, can be paged out of RAM if the system
83wants to use that memory elsewhere.</p>
84
85
86<h3 id="SharingRAM">Sharing Memory</h3>
87
88<p>In order to fit everything it needs in RAM, Android tries to share RAM pages across processes. It
89can do so in the following ways:</p>
90<ul>
91<li>Each app process is forked from an existing process called Zygote.
92The Zygote process starts when the system boots and loads common framework code and resources
93(such as activity themes). To start a new app process, the system forks the Zygote process then
94loads and runs the app's code in the new process. This allows most of the RAM pages allocated for
95framework code and resources to be shared across all app processes.</li>
96
97<li>Most static data is mmapped into a process. This not only allows that same data to be shared
98between processes but also allows it to be paged out when needed. Example static data include:
99Dalvik code (by placing it in a pre-linked {@code .odex} file for direct mmapping), app resources
100(by designing the resource table to be a structure that can be mmapped and by aligning the zip
101entries of the APK), and traditional project elements like native code in {@code .so} files.</li>
102
103<li>In many places, Android shares the same dynamic RAM across processes using explicitly allocated
104shared memory regions (either with ashmem or gralloc). For example, window surfaces use shared
105memory between the app and screen compositor, and cursor buffers use shared memory between the
106content provider and client.</li>
107</ul>
108
109<p>Due to the extensive use of shared memory, determining how much memory your app is using requires
110care. Techniques to properly determine your app's memory use are discussed in <a
111href="{@docRoot}tools/debugging/debugging-memory.html">Investigating Your RAM Usage</a>.</p>
112
113
114<h3 id="AllocatingRAM">Allocating and Reclaiming App Memory</h3>
115
116<p>Here are some facts about how Android allocates then reclaims memory from your app:</p>
117
118<ul>
119<li>The Dalvik heap for each process is constrained to a single virtual memory range. This defines
120the logical heap size, which can grow as it needs to (but only up to a limit that the system defines
121for each app).</li>
122
123<li>The logical size of the heap is not the same as the amount of physical memory used by the heap.
124When inspecting your app's heap, Android computes a value called the Proportional Set Size (PSS),
125which accounts for both dirty and clean pages that are shared with other processes&mdash;but only in an
126amount that's proportional to how many apps share that RAM. This (PSS) total is what the system
127considers to be your physical memory footprint. For more information about PSS, see the <a
128href="{@docRoot}tools/debugging/debugging-memory.html#ViewingAllocations">Investigating Your
129RAM Usage</a> guide.</li>
130
131<li>The Dalvik heap does not compact the logical size of the heap, meaning that Android does not
132defragment the heap to close up space. Android can only shrink the logical heap size when there
133is unused space at the end of the heap. But this doesn't mean the physical memory used by the heap
134can't shrink. After garbage collection, Dalvik walks the heap and finds unused pages, then returns
135those pages to the kernel using madvise. So, paired allocations and deallocations of large
136chunks should result in reclaiming all (or nearly all) the physical memory used. However,
137reclaiming memory from small allocations can be much less efficient because the page used
138for a small allocation may still be shared with something else that has not yet been freed.</li>
139</ul>
140
141
142<h3 id="RestrictingMemory">Restricting App Memory</h3>
143
144<p>To maintain a functional multi-tasking environment, Android sets a hard limit on the heap size
145for each app. The exact heap size limit varies between devices based on how much RAM the device
146has available overall. If your app has reached the heap capacity and tries to allocate more
147memory, it will receive an {@link java.lang.OutOfMemoryError}.</p>
148
149<p>In some cases, you might want to query the system to determine exactly how much heap space you
150have available on the current device&mdash;for example, to determine how much data is safe to keep in a
151cache. You can query the system for this figure by calling {@link
152android.app.ActivityManager#getMemoryClass()}. This returns an integer indicating the number of
153megabytes available for your app's heap. This is discussed further below, under
154<a href="#CheckHowMuchMemory">Check how much memory you should use</a>.</p>
155
156
157<h3 id="SwitchingApps">Switching Apps</h3>
158
159<p>Instead of using swap space when the user switches between apps, Android keeps processes that
160are not hosting a foreground ("user visible") app component in a least-recently used (LRU) cache.
161For example, when the user first launches an app, a process is created for it, but when the user
162leaves the app, that process does <em>not</em> quit. The system keeps the process cached, so if
163the user later returns to the app, the process is reused for faster app switching.</p>
164
165<p>If your app has a cached process and it retains memory that it currently does not need,
166then your app&mdash;even while the user is not using it&mdash;is constraining the system's
167overall performance. So, as the system runs low on memory, it may kill processes in the LRU cache
168beginning with the process least recently used, but also giving some consideration toward
169which processes are most memory intensive. To keep your process cached as long as possible, follow
170the advice in the following sections about when to release your references.</p>
171
172<p>More information about how processes are cached while not running in the foreground and how
173Android decides which ones
174can be killed is available in the <a href="{@docRoot}guide/components/processes-and-threads.html"
175>Processes and Threads</a> guide.</p>
176
177
178
179
180<h2 id="YourApp">How Your App Should Manage Memory</h2>
181
182<p>You should consider RAM constraints throughout all phases of development, including during app
183design (before you begin development). There are many
184ways you can design and write code that lead to more efficient results, through aggregation of the
185same techniques applied over and over.</p>
186
187<p>You should apply the following techniques while designing and implementing your app to make it
188more memory efficient.</p>
189
190
191<h3 id="Services">Use services sparingly</h3>
192
193<p>If your app needs a <a href="{@docRoot}guide/components/services.html">service</a>
194to perform work in the background, do not keep it running unless
195it's actively performing a job. Also be careful to never leak your service by failing to stop it
196when its work is done.</p>
197
198<p>When you start a service, the system prefers to always keep the process for that service
199running. This makes the process very expensive because the RAM used by the service can’t be used by
200anything else or paged out. This reduces the number of cached processes that the system can keep in
201the LRU cache, making app switching less efficient. It can even lead to thrashing in the system
202when memory is tight and the system can’t maintain enough processes to host all the services
203currently running.</p>
204
205<p>The best way to limit the lifespan of your service is to use an {@link
206android.app.IntentService}, which finishes
207itself as soon as it's done handling the intent that started it. For more information, read
208<a href="{@docRoot}training/run-background-service/index.html">Running in a Background Service</a>
209.</p>
210
211<p>Leaving a service running when it’s not needed is <strong>one of the worst memory-management
212mistakes</strong> an Android app can make. So don’t be greedy by keeping a service for your app
213running. Not only will it increase the risk of your app performing poorly due to RAM constraints,
214but users will discover such misbehaving apps and uninstall them.</p>
215
216
217<h3 id="ReleaseMemoryAsUiGone">Release memory when your user interface becomes hidden</h3>
218
219<p>When the user navigates to a different app and your UI is no longer visible, you should
220release any resources that are used by only your UI. Releasing UI resources at this time can
221significantly increase the system's capacity for cached processes, which has a direct impact on the
222quality of the user experience.</p>
223
224<p>To be notified when the user exits your UI, implement the {@link
225android.content.ComponentCallbacks2#onTrimMemory onTrimMemory()} callback in your {@link
226android.app.Activity} classes. You should use this
227method to listen for the {@link android.content.ComponentCallbacks2#TRIM_MEMORY_UI_HIDDEN} level,
228which indicates your UI is now hidden from view and you should free resources that only your UI
229uses.</p>
230
231
232<p>Notice that your app receives the {@link android.content.ComponentCallbacks2#onTrimMemory
233onTrimMemory()} callback with {@link android.content.ComponentCallbacks2#TRIM_MEMORY_UI_HIDDEN}
234only when <em>all the UI components</em> of your app process become hidden from the user.
235This is distinct
236from the {@link android.app.Activity#onStop onStop()} callback, which is called when an {@link
237android.app.Activity} instance becomes hidden, which occurs even when the user moves to
238another activity in your app. So although you should implement {@link android.app.Activity#onStop
239onStop()} to release activity resources such as a network connection or to unregister broadcast
240receivers, you usually should not release your UI resources until you receive {@link
241android.content.ComponentCallbacks2#onTrimMemory onTrimMemory(TRIM_MEMORY_UI_HIDDEN)}. This ensures
242that if the user navigates <em>back</em> from another activity in your app, your UI resources are
243still available to resume the activity quickly.</p>
244
245
246
247<h3 id="ReleaseMemoryAsTight">Release memory as memory becomes tight</h3>
248
249<p>During any stage of your app's lifecycle, the {@link
250android.content.ComponentCallbacks2#onTrimMemory onTrimMemory()} callback also tells you when
251the overall device memory is getting low. You should respond by further releasing resources based
252on the following memory levels delivered by {@link android.content.ComponentCallbacks2#onTrimMemory
253onTrimMemory()}:</p>
254
255<ul>
256<li>{@link android.content.ComponentCallbacks2#TRIM_MEMORY_RUNNING_MODERATE}
257<p>Your app is running and not considered killable, but the device is running low on memory and the
258system is actively killing processes in the LRU cache.</p>
259</li>
260
261<li>{@link android.content.ComponentCallbacks2#TRIM_MEMORY_RUNNING_LOW}
262<p>Your app is running and not considered killable, but the device is running much lower on
263memory so you should release unused resources to improve system performance (which directly
264impacts your app's performance).</p>
265</li>
266
267<li>{@link android.content.ComponentCallbacks2#TRIM_MEMORY_RUNNING_CRITICAL}
268<p>Your app is still running, but the system has already killed most of the processes in the
269LRU cache, so you should release all non-critical resources now. If the system cannot reclaim
270sufficient amounts of RAM, it will clear all of the LRU cache and begin killing processes that
271the system prefers to keep alive, such as those hosting a running service.</p>
272</li>
273</ul>
274
275<p>Also, when your app process is currently cached, you may receive one of the following
276levels from {@link android.content.ComponentCallbacks2#onTrimMemory onTrimMemory()}:</p>
277<ul>
278<li>{@link android.content.ComponentCallbacks2#TRIM_MEMORY_BACKGROUND}
279<p>The system is running low on memory and your process is near the beginning of the LRU list.
280Although your app process is not at a high risk of being killed, the system may already be killing
281processes in the LRU cache. You should release resources that are easy to recover so your process
282will remain in the list and resume quickly when the user returns to your app.</p>
283</li>
284
285<li>{@link android.content.ComponentCallbacks2#TRIM_MEMORY_MODERATE}
286<p>The system is running low on memory and your process is near the middle of the LRU list. If the
287system becomes further constrained for memory, there's a chance your process will be killed.</p>
288</li>
289
290<li>{@link android.content.ComponentCallbacks2#TRIM_MEMORY_COMPLETE}
291<p>The system is running low on memory and your process is one of the first to be killed if the
292system does not recover memory now. You should release everything that's not critical to
293resuming your app state.</p>
294
295</li>
296</ul>
297
298<p>Because the {@link android.content.ComponentCallbacks2#onTrimMemory onTrimMemory()} callback was
299added in API level 14, you can use the {@link android.content.ComponentCallbacks#onLowMemory()}
300callback as a fallback for older versions, which is roughly equivalent to the {@link
301android.content.ComponentCallbacks2#TRIM_MEMORY_COMPLETE} event.</p>
302
303<p class="note"><strong>Note:</strong> When the system begins killing processes in the LRU cache,
304although it primarily works bottom-up, it does give some consideration to which processes are
305consuming more memory and will thus provide the system more memory gain if killed.
306So the less memory you consume while in the LRU list overall, the better your chances are
307to remain in the list and be able to quickly resume.</p>
308
309
310
311<h3 id="CheckHowMuchMemory">Check how much memory you should use</h3>
312
313<p>As mentioned earlier, each Android-powered device has a different amount of RAM available to the
314system and thus provides a different heap limit for each app. You can call {@link
315android.app.ActivityManager#getMemoryClass()} to get an estimate of your app's available heap in
316megabytes. If your app tries to allocate more memory than is available here, it will receive an
317{@link java.lang.OutOfMemoryError}.</p>
318
319<p>In very special situations, you can request a larger heap size by setting the <a
320href="{@docRoot}guide/topics/manifest/application-element.html#largeHeap">{@code largeHeap}</a>
321attribute to "true" in the manifest <a
322href="{@docRoot}guide/topics/manifest/application-element.html">{@code &lt;application&gt;}</a>
323tag. If you do so, you can call {@link
324android.app.ActivityManager#getLargeMemoryClass()} to get an estimate of the large heap size.</p>
325
326<p>However, the ability to request a large heap is intended only for a small set of apps that can
327justify the need to consume more RAM (such as a large photo editing app). <strong>Never request a
328large heap simply because you've run out of memory</strong> and you need a quick fix&mdash;you
329should use it only when you know exactly where all your memory is being allocated and why it must
330be retained. Yet, even when you're confident your app can justify the large heap, you should avoid
331requesting it to whatever extent possible. Using the extra memory will increasingly be to the
332detriment of the overall user experience because garbage collection will take longer and system
333performance may be slower when task switching or performing other common operations.</p>
334
335<p>Additionally, the large heap size is not the same on all devices and, when running on
336devices that have limited RAM, the large heap size may be exactly the same as the regular heap
337size. So even if you do request the large heap size, you should call {@link
338android.app.ActivityManager#getMemoryClass()} to check the regular heap size and strive to always
339stay below that limit.</p>
340
341
342<h3 id="Bitmaps">Avoid wasting memory with bitmaps</h3>
343
344<p>When you load a bitmap, keep it in RAM only at the resolution you need for the current device's
345screen, scaling it down if the original bitmap is a higher resolution. Keep in mind that an
346increase in bitmap resolution results in a corresponding (increase<sup>2</sup>) in memory needed,
347because both the X and Y dimensions increase.</p>
348
349<p class="note"><strong>Note:</strong> On Android 2.3.x (API level 10) and below, bitmap objects
350always appear as the same size in your app heap regardless of the image resolution (the actual
351pixel data is stored separately in native memory). This makes it more difficult to debug the bitmap
352memory allocation because most heap analysis tools do not see the native allocation. However,
353beginning in Android 3.0 (API level 11), the bitmap pixel data is allocated in your app's Dalvik
354heap, improving garbage collection and debuggability. So if your app uses bitmaps and you're having
355trouble discovering why your app is using some memory on an older device, switch to a device
356running Android 3.0 or higher to debug it.</p>
357
358<p>For more tips about working with bitmaps, read <a
359href="{@docRoot}training/displaying-bitmaps/manage-memory.html">Managing Bitmap Memory</a>.</p>
360
361
362<h3 id="DataContainers">Use optimized data containers</h3>
363
364<p>Take advantage of optimized containers in the Android framework, such as {@link
365android.util.SparseArray}, {@link android.util.SparseBooleanArray}, and {@link
366android.support.v4.util.LongSparseArray}. The generic {@link java.util.HashMap}
367implementation can be quite memory
368inefficient because it needs a separate entry object for every mapping. Additionally, the {@link
369android.util.SparseArray} classes are more efficient because they avoid the system's need
370to <acronym title=
371"Automatic conversion from primitive types to object classes (such as int to Integer)"
372>autobox</acronym>
373the key and sometimes value (which creates yet another object or two per entry). And don't be
374afraid of dropping down to raw arrays when that makes sense.</p>
375
376
377
378<h3 id="Overhead">Be aware of memory overhead</h3>
379
380<p>Be knowledgeable about the cost and overhead of the language and libraries you are using, and
381keep this information in mind when you design your app, from start to finish. Often, things on the
382surface that look innocuous may in fact have a large amount of overhead. Examples include:</p>
383<ul>
384<li>Enums often require more than twice as much memory as static constants. You should strictly
385avoid using enums on Android.</li>
386
387<li>Every class in Java (including anonymous inner classes) uses about 500 bytes of code.</li>
388
389<li>Every class instance has 12-16 bytes of RAM overhead.</li>
390
391<li>Putting a single entry into a {@link java.util.HashMap} requires the allocation of an
392additional entry object that takes 32 bytes (see the previous section about <a
393href="#DataContainers">optimized data containers</a>).</li>
394</ul>
395
396<p>A few bytes here and there quickly add up—app designs that are class- or object-heavy will suffer
397from this overhead. That can leave you in the difficult position of looking at a heap analysis and
398realizing your problem is a lot of small objects using up your RAM.</p>
399
400
401<h3 id="Abstractions">Be careful with code abstractions</h3>
402
403<p>Often, developers use abstractions simply as a "good programming practice," because abstractions
404can improve code flexibility and maintenance. However, abstractions come at a significant cost:
405generally they require a fair amount more code that needs to be executed, requiring more time and
406more RAM for that code to be mapped into memory. So if your abstractions aren't supplying a
407significant benefit, you should avoid them.</p>
408
409
410<h3 id="NanoProto">Use nano protobufs for serialized data</h3>
411
412<p><a href="https://developers.google.com/protocol-buffers/docs/overview">Protocol
413buffers</a> are a language-neutral, platform-neutral, extensible mechanism designed by Google for
414serializing structured data&mdash;think XML, but smaller, faster, and simpler. If you decide to use
415protobufs for your data, you should always use nano protobufs in your client-side code. Regular
416protobufs generate extremely verbose code, which will cause many kinds of problems in your app:
417increased RAM use, significant APK size increase, slower execution, and quickly hitting the DEX
418symbol limit.</p>
419
420<p>For more information, see the "Nano version" section in the <a
421href="https://android.googlesource.com/platform/external/protobuf/+/master/java/README.txt"
422class="external-link">protobuf readme</a>.</p>
423
424
425
426<h3 id="DependencyInjection">Avoid dependency injection frameworks</h3>
427
428<p>Using a dependency injection framework such as <a
429href="https://code.google.com/p/google-guice/" class="external-link">Guice</a> or
430<a href="https://github.com/roboguice/roboguice" class="external-link">RoboGuice</a> may be
431attractive because they can simplify the code you write and provide an adaptive environment
432that's useful for testing and other configuration changes. However, these frameworks tend to perform
433a lot of process initialization by scanning your code for annotations, which can require significant
434amounts of your code to be mapped into RAM even though you don't need it. These mapped pages are
435allocated into clean memory so Android can drop them, but that won't happen until the pages have
436been left in memory for a long period of time.</p>
437
438
439<h3 id="ExternalLibs">Be careful about using external libraries</h3>
440
441<p>External library code is often not written for mobile environments and can be inefficient when used
442for work on a mobile client. At the very least, when you decide to use an external library, you
443should assume you are taking on a significant porting and maintenance burden to optimize the
444library for mobile. Plan for that work up-front and analyze the library in terms of code size and
445RAM footprint before deciding to use it at all.</p>
446
447<p>Even libraries supposedly designed for use on Android are potentially dangerous because each
448library may do things differently. For example, one library may use nano protobufs while another
449uses micro protobufs. Now you have two different protobuf implementations in your app. This can and
450will also happen with different implementations of logging, analytics, image loading frameworks,
451caching, and all kinds of other things you don't expect. <a
452href="{@docRoot}tools/help/proguard.html">ProGuard</a> won't save you here because these
453will all be lower-level dependencies that are required by the features for which you want the
454library. This becomes especially problematic when you use an {@link android.app.Activity}
455subclass from a library (which
456will tend to have wide swaths of dependencies), when libraries use reflection (which is common and
457means you need to spend a lot of time manually tweaking ProGuard to get it to work), and so on.</p>
458
459<p>Also be careful not to fall into the trap of using a shared library for one or two features out of
460dozens of other things it does; you don't want to pull in a large amount of code and overhead that
461you don't even use. At the end of the day, if there isn't an existing implementation that is a
462strong match for what you need to do, it may be best if you create your own implementation.</p>
463
464
465<h3 id="OverallPerf">Optimize overall performance</h3>
466
467<p>A variety of information about optimizing your app's overall performance is available
468in other documents listed in <a href="{@docRoot}training/best-performance.html">Best Practices
469for Performance</a>. Many of these documents include optimizations tips for CPU performance, but
470many of these tips also help optimize your app's memory use, such as by reducing the number of
471layout objects required by your UI.</p>
472
473<p>You should also read about <a href="{@docRoot}tools/debugging/debugging-ui.html">optimizing
474your UI</a> with the layout debugging tools and take advantage of
475the optimization suggestions provided by the <a
476href="{@docRoot}tools/debugging/improving-w-lint.html">lint tool</a>.</p>
477
478
479<h3 id="Proguard">Use ProGuard to strip out any unneeded code</h3>
480
481<p>The <a href="{@docRoot}tools/help/proguard.html">ProGuard</a> tool shrinks,
482optimizes, and obfuscates your code by removing unused code and renaming classes, fields, and
483methods with semantically obscure names. Using ProGuard can make your code more compact, requiring
484fewer RAM pages to be mapped.</p>
485
486
487<h3 id="Zipalign">Use zipalign on your final APK</h3>
488
489<p>If you do any post-processing of an APK generated by a build system (including signing it
490with your final production certificate), then you must run <a
491href="{@docRoot}tools/help/zipalign.html">zipalign</a> on it to have it re-aligned.
492Failing to do so can cause your app to require significantly more RAM, because things like
493resources can no longer be mmapped from the APK.</p>
494
495<p class="note"><strong>Note:</strong> Google Play Store does not accept APK files that
496are not zipaligned.</p>
497
498
499<h3 id="AnalyzeRam">Analyze your RAM usage</h3>
500
501<p>Once you achieve a relatively stable build, begin analyzing how much RAM your app is using
502throughout all stages of its lifecycle. For information about how to analyze your app, read <a
503href="{@docRoot}tools/debugging/debugging-memory.html">Investigating Your RAM Usage</a>.</p>
504
505
506
507
508<h3 id="MultipleProcesses">Use multiple processes</h3>
509
510<p>If it's appropriate for your app, an advanced technique that may help you manage your app's
511memory is dividing components of your app into multiple processes. This technique must always be
512used carefully and <strong>most apps should not run multiple processes</strong>, as it can easily
513increase&mdash;rather than decrease&mdash;your RAM footprint if done incorrectly. It is primarily
514useful to apps that may run significant work in the background as well as the foreground and can
515manage those operations separately.</p>
516
517
518<p>An example of when multiple processes may be appropriate is when building a music player that
519plays music from a service for long period of time. If
520the entire app runs in one process, then many of the allocations performed for its activity UI must
521be kept around as long as it is playing music, even if the user is currently in another app and the
522service is controlling the playback. An app like this may be split into two process: one for its
523UI, and the other for the work that continues running in the background service.</p>
524
525<p>You can specify a separate process for each app component by declaring the <a href=
526"{@docRoot}guide/topics/manifest/service-element.html#proc">{@code android:process}</a> attribute
527for each component in the manifest file. For example, you can specify that your service should run
528in a process separate from your app's main process by declaring a new process named "background"
529(but you can name the process anything you like):</p>
530
531<pre>
532&lt;service android:name=".PlaybackService"
533 android:process=":background" />
534</pre>
535
536<p>Your process name should begin with a colon (':') to ensure that the process remains private to
537your app.</p>
538
539<p>Before you decide to create a new process, you need to understand the memory implications.
540To illustrate the consequences of each process, consider that an empty process doing basically
541nothing has an extra memory footprint of about 1.4MB, as shown by the memory information
542dump below.</p>
543
544<pre class="no-pretty-print">
545adb shell dumpsys meminfo com.example.android.apis:empty
546
547** MEMINFO in pid 10172 [com.example.android.apis:empty] **
548 Pss Pss Shared Private Shared Private Heap Heap Heap
549 Total Clean Dirty Dirty Clean Clean Size Alloc Free
550 ------ ------ ------ ------ ------ ------ ------ ------ ------
551 Native Heap 0 0 0 0 0 0 1864 1800 63
552 Dalvik Heap 764 0 5228 316 0 0 5584 5499 85
553 Dalvik Other 619 0 3784 448 0 0
554 Stack 28 0 8 28 0 0
555 Other dev 4 0 12 0 0 4
556 .so mmap 287 0 2840 212 972 0
557 .apk mmap 54 0 0 0 136 0
558 .dex mmap 250 148 0 0 3704 148
559 Other mmap 8 0 8 8 20 0
560 Unknown 403 0 600 380 0 0
561 TOTAL 2417 148 12480 1392 4832 152 7448 7299 148
562</pre>
563
564<p class="note"><strong>Note:</strong> More information about how to read this output is provided
565in <a href="{@docRoot}tools/debugging/debugging-memory.html#ViewingAllocations">Investigating
566Your RAM Usage</a>. The key data here is the <em>Private Dirty</em> and <em>Private
567Clean</em> memory, which shows that this process is using almost 1.4MB of non-pageable RAM
568(distributed across the Dalvik heap, native allocations, book-keeping, and library-loading),
569and another 150K of RAM for code that has been mapped in to execute.</p>
570
571<p>This memory footprint for an empty process is fairly significant and it can quickly
572grow as you start doing work in that process. For
573example, here is the memory use of a process that is created only to show an activity with some
574text in it:</p>
575
576<pre class="no-pretty-print">
577** MEMINFO in pid 10226 [com.example.android.helloactivity] **
578 Pss Pss Shared Private Shared Private Heap Heap Heap
579 Total Clean Dirty Dirty Clean Clean Size Alloc Free
580 ------ ------ ------ ------ ------ ------ ------ ------ ------
581 Native Heap 0 0 0 0 0 0 3000 2951 48
582 Dalvik Heap 1074 0 4928 776 0 0 5744 5658 86
583 Dalvik Other 802 0 3612 664 0 0
584 Stack 28 0 8 28 0 0
585 Ashmem 6 0 16 0 0 0
586 Other dev 108 0 24 104 0 4
587 .so mmap 2166 0 2824 1828 3756 0
588 .apk mmap 48 0 0 0 632 0
589 .ttf mmap 3 0 0 0 24 0
590 .dex mmap 292 4 0 0 5672 4
591 Other mmap 10 0 8 8 68 0
592 Unknown 632 0 412 624 0 0
593 TOTAL 5169 4 11832 4032 10152 8 8744 8609 134
594</pre>
595
596<p>The process has now almost tripled in size, to 4MB, simply by showing some text in the UI. This
597leads to an important conclusion: If you are going to split your app into multiple processes, only
598one process should be responsible for UI. Other processes should avoid any UI, as this will quickly
599increase the RAM required by the process (especially once you start loading bitmap assets and other
600resources). It may then be hard or impossible to reduce the memory usage once the UI is drawn.</p>
601
602<p>Additionally, when running more than one process, it's more important than ever that you keep your
603code as lean as possible, because any unnecessary RAM overhead for common implementations are now
604replicated in each process. For example, if you are using enums (though <a
605href="#Overhead">you should not use enums</a>), all of
606the RAM needed to create and initialize those constants is duplicated in each process, and any
607abstractions you have with adapters and temporaries or other overhead will likewise be replicated.</p>
608
609<p>Another concern with multiple processes is the dependencies that exist between them. For example,
610if your app has a content provider that you have running in the default process which also hosts
611your UI, then code in a background process that uses that content provider will also require that
612your UI process remain in RAM. If your goal is to have a background process that can run
613independently of a heavy-weight UI process, it can't have dependencies on content providers or
614services that execute in the UI process.</p>
615
616
617
618
619
620
621
622
623
624
625<!-- THE FOLLOWING IS OVERWHELMING AND NOT NECESSARY FOR MOST APPS, LEAVING OUT FOR NOW
626
627
628<p>You can examine the dependencies between your processes with the command:</p>
629
630<pre class="no-pretty-print">
631adb shell dumpsys activity
632</pre>
633
634<p>This dumps various information about the Activity Manager's state, ending with a list of all
635processes in their memory management order, including the reason each process is at its given
636level. For example, below is a dump with the Music app in the foreground.</p>
637
638<pre class="no-pretty-print">
639ACTIVITY MANAGER RUNNING PROCESSES (dumpsys activity processes)
640 Process LRU list (sorted by oom_adj):
641 PERS # 4: adj=sys /F trm= 0 20674:system/1000 (fixed)
642 PERS #39: adj=pers /F trm= 0 20964:com.android.nfc/1027 (fixed)
643 PERS # 2: adj=pers /F trm= 0 20959:com.android.phone/1001 (fixed)
644 PERS # 1: adj=pers /F trm= 0 20779:com.android.systemui/u0a10057 (fixed)
645 Proc #11: adj=fore /FA trm= 0 8663:com.google.android.music:ui/u0a10043 (top-activity)
646 Proc #10: adj=fore /F trm= 0 30881:com.google.android.music:main/u0a10043 (provider)
647 com.google.android.music/.store.MusicContentProvider<=Proc{8663:com.google.android.music:ui/u0a10043}
648 Proc # 6: adj=fore /F trm= 0 21014:com.google.process.gapps/u0a10023 (provider)
649 com.google.android.gsf/.settings.GoogleSettingsProvider<=Proc{20935:com.google.process.location/u0a10023}
650 Proc #38: adj=vis /F trm= 0 21028:com.android.nfc:handover/1027 (service)
651 com.android.nfc/.handover.HandoverService<=Proc{20964:com.android.nfc/1027}
652 Proc # 7: adj=vis /B trm= 0 20935:com.google.process.location/u0a10023 (service)
653 com.google.android.location/.GeocodeService<=Proc{20674:system/1000}
654 Proc # 3: adj=vis /F trm= 0 21225:com.android.bluetooth/1002 (service)
655 com.android.bluetooth/.hfp.HeadsetService<=Proc{20674:system/1000}
656 Proc # 0: adj=vis /F trm= 0 20908:com.google.android.inputmethod.latin/u0a10035 (service)
657 com.google.android.inputmethod.latin/com.android.inputmethod.latin.LatinIME<=Proc{20674:system/1000}
658 Proc #34: adj=svc /B trm= 0 16765:com.google.android.apps.currents/u0a10012 (started-services)
659 Proc #14: adj=svc /B trm= 0 21148:com.google.android.gms/u0a10023 (started-services)
660 Proc #12: adj=home /B trm= 0 20989:com.android.launcher/u0a10036 (home)
661 Proc #37: adj=svcb /B trm= 0 15194:com.google.android.apps.googlevoice/u0a10089 (started-services)
662 Proc #17: adj=svcb /B trm= 0 24537:android.process.media/u0a10016 (started-services)
663 Proc #35: adj=bak /B trm= 0 16087:com.android.defcontainer/u0a10013 (service)
664 com.android.defcontainer/.DefaultContainerService<=Proc{16050:com.android.settings/1000}
665 Proc #16: adj=bak /B trm= 0 7334:com.google.android.gm/u0a10022 (bg-act)
666 Proc #15: adj=bak /B trm= 0 22499:com.google.android.googlequicksearchbox/u0a10060 (bg-act)
667 Proc # 9: adj=bak /B trm= 0 20856:com.google.android.gsf.login/u0a10023 (bg-empty)
668 Proc #26: adj=bak+1/B trm= 0 9923:com.android.mms/u0a10042 (bg-act)
669 Proc #23: adj=bak+1/B trm= 0 16721:com.android.chrome/u0a10010 (bg-act)
670 Proc #22: adj=bak+1/B trm= 0 17596:com.android.chrome:sandboxed_process0/u0a10010i33 (service)
671 com.android.chrome/org.chromium.content.app.SandboxedProcessService0<=Proc{16721:com.android.chrome/u0a10010}
672 Proc #19: adj=bak+1/B trm= 0 17442:com.google.android.youtube/u0a10067 (bg-services)
673 Proc #18: adj=bak+2/B trm= 0 16740:com.google.android.apps.plus/u0a10052 (bg-empty)
674 Proc #13: adj=bak+2/B trm= 0 7707:com.android.musicfx/u0a10044 (bg-empty)
675 Proc #36: adj=bak+3/B trm= 0 16050:com.android.settings/1000 (bg-act)
676 Proc #33: adj=bak+3/B trm= 0 16863:com.android.dialer/u0a10015 (bg-act)
677</pre>
678
679
680<p class="note"><strong>Note:</strong> The exact details of what is shown here will vary across
681platform versions as process management policies are tweaked and improved.</p>
682
683
684<p>Details on the highlighted sections are:</p>
685
686<ol>
687<li>Foreground app: This is the current app running in the foreground -- it is in the "fore" memory
688class because it is the top activity on the activity stack.</li>
689
690<li>Persistent processes: These are processes that are part of the core system that must always be
691running.</li>
692
693<li>Dependent process: This shows how the Music app is using two processes. Its UI process has a
694dependency on the "main" process (through a content provider). So while the UI process is in use,
695the main process must also be kept around. This means the app's memory footprint is actually the
696sum of both processes. You will have this kind of connection on a content provider any time you
697have active calls into it or have unclosed cursors or file streams that came from it.</li>
698
699<li>Visible processes: These are processes that count in some way as "visible" to the user. This
700generally means that it is either something the user can literally see (such as a process hosting a
701paused but visible activity that is behind a non-full-screen dialog) or is something the user might
702notice if the process disappeared (such as a foreground service playing music). You should be
703certain that any process you have running at the "visible" level is indeed critical to the user,
704because they are very expensive to the overall RAM load.</li>
705
706<li>Service processes: These are processes running long-term jobs in a service. This level of the
707list is the start of less-critical processes, which the system has some freedom to kill if RAM is
708needed elsewhere. These services are still quite expensive because they can be killed only
709temporarily and the system tries to keep them running whenever possible.</li>
710
711<li>Home process: A special slot for the process that hosts the current Home activity, to try to
712prevent it from being killed as much as possible. Killing this process is much more damaging to the
713user experience than killing other cached processes, because so much user interaction goes through
714home.</li>
715
716<li>Secondary service processes: These are services that have been running for a relatively long time
717and so should be killed more aggressively when RAM is needed elsewhere.</li>
718
719<li>Cached processes: These are cached processes held in the LRU cache, which allow for fast app
720switching and component launching. These processes are not required and the system will kill them
721as needed to reclaim memory. You will often see a process hosting a running service here—this is
722part of a platform policy of allowing very long-running services to drop down into the LRU list and
723eventually be killed. If the service should continue running (as defined by the {@link
724android.app.Service#onStartCommand onStartCommand()} return value, such as {@link
725android.app.Service#START_STICKY}), the the system eventually restarts it. This avoids issues with
726such services having memory leaks that over time reduce the number of regular cached processes that
727can be kept.</li>
728
729</ol>
730
731<p>This numbered list of processes is essentially the LRU list of processes that the framework
732provides to the kernel to help it determine which processes it should kill as it needs more RAM.
733The kernel's out of memory killer will generally begin from the bottom of this list, killing the
734last process and working its way up. It may not do it in exactly this order, as it can also take
735into consideration other factors such as the relative RAM footprint of processes to some degree.</p>
736
737<p>There are many other options you can use with the activity command to analyze further details of
738your app's state&mdash;use <code>adb shell dumpsys activity -h</code> for help on its use.</p>
739
740-->