Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 1 | page.title=Managing Your App's Memory |
| 2 | page.tags="ram","low memory","OutOfMemoryError","onTrimMemory" |
| 3 | page.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 |
| 52 | it's even more valuable on a mobile operating system where physical memory is often constrained. |
| 53 | Although Android's Dalvik virtual machine performs routine garbage collection, this doesn't allow |
| 54 | you 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 |
| 57 | introducing memory leaks (usually caused by holding onto object references in global members) and |
| 58 | release any {@link java.lang.ref.Reference} objects at the appropriate time (as defined by |
| 59 | lifecycle callbacks discussed further below). For most apps, the Dalvik garbage collector takes |
| 60 | care of the rest: the system reclaims your memory allocations when the corresponding objects leave |
| 61 | the 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 |
| 64 | proactively reduce memory usage while developing for Android. For more information about general |
| 65 | practices to clean up your resources when programming in Java, refer to other books or online |
| 66 | documentation about managing resource references. If you’re looking for information about how to |
| 67 | analyze your app’s memory once you’ve already built it, read <a |
| 68 | href="{@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—whether by allocating |
| 79 | new objects or touching mmapped pages—remains resident in RAM and cannot be paged out. |
| 80 | So the only way to completely release memory from your app is to release object references you may |
| 81 | be holding, making the memory available to the garbage collector. That is with one exception: |
| 82 | any files mmapped in without modification, such as code, can be paged out of RAM if the system |
| 83 | wants 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 |
| 89 | can do so in the following ways:</p> |
| 90 | <ul> |
| 91 | <li>Each app process is forked from an existing process called Zygote. |
| 92 | The 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 |
| 94 | loads and runs the app's code in the new process. This allows most of the RAM pages allocated for |
| 95 | framework 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 |
| 98 | between processes but also allows it to be paged out when needed. Example static data include: |
| 99 | Dalvik 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 |
| 101 | entries 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 |
| 104 | shared memory regions (either with ashmem or gralloc). For example, window surfaces use shared |
| 105 | memory between the app and screen compositor, and cursor buffers use shared memory between the |
| 106 | content 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 |
| 110 | care. Techniques to properly determine your app's memory use are discussed in <a |
| 111 | href="{@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 |
| 120 | the logical heap size, which can grow as it needs to (but only up to a limit that the system defines |
| 121 | for 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. |
| 124 | When inspecting your app's heap, Android computes a value called the Proportional Set Size (PSS), |
| 125 | which accounts for both dirty and clean pages that are shared with other processes—but only in an |
| 126 | amount that's proportional to how many apps share that RAM. This (PSS) total is what the system |
| 127 | considers to be your physical memory footprint. For more information about PSS, see the <a |
| 128 | href="{@docRoot}tools/debugging/debugging-memory.html#ViewingAllocations">Investigating Your |
| 129 | RAM Usage</a> guide.</li> |
| 130 | |
| 131 | <li>The Dalvik heap does not compact the logical size of the heap, meaning that Android does not |
| 132 | defragment the heap to close up space. Android can only shrink the logical heap size when there |
| 133 | is unused space at the end of the heap. But this doesn't mean the physical memory used by the heap |
| 134 | can't shrink. After garbage collection, Dalvik walks the heap and finds unused pages, then returns |
| 135 | those pages to the kernel using madvise. So, paired allocations and deallocations of large |
| 136 | chunks should result in reclaiming all (or nearly all) the physical memory used. However, |
| 137 | reclaiming memory from small allocations can be much less efficient because the page used |
| 138 | for 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 |
| 145 | for each app. The exact heap size limit varies between devices based on how much RAM the device |
| 146 | has available overall. If your app has reached the heap capacity and tries to allocate more |
| 147 | memory, 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 |
| 150 | have available on the current device—for example, to determine how much data is safe to keep in a |
| 151 | cache. You can query the system for this figure by calling {@link |
| 152 | android.app.ActivityManager#getMemoryClass()}. This returns an integer indicating the number of |
| 153 | megabytes 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 |
| 160 | are not hosting a foreground ("user visible") app component in a least-recently used (LRU) cache. |
| 161 | For example, when the user first launches an app, a process is created for it, but when the user |
| 162 | leaves the app, that process does <em>not</em> quit. The system keeps the process cached, so if |
| 163 | the 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, |
| 166 | then your app—even while the user is not using it—is constraining the system's |
| 167 | overall performance. So, as the system runs low on memory, it may kill processes in the LRU cache |
| 168 | beginning with the process least recently used, but also giving some consideration toward |
| 169 | which processes are most memory intensive. To keep your process cached as long as possible, follow |
| 170 | the 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 |
| 173 | Android decides which ones |
| 174 | can 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 |
| 183 | design (before you begin development). There are many |
| 184 | ways you can design and write code that lead to more efficient results, through aggregation of the |
| 185 | same techniques applied over and over.</p> |
| 186 | |
| 187 | <p>You should apply the following techniques while designing and implementing your app to make it |
| 188 | more 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> |
| 194 | to perform work in the background, do not keep it running unless |
| 195 | it's actively performing a job. Also be careful to never leak your service by failing to stop it |
| 196 | when its work is done.</p> |
| 197 | |
| 198 | <p>When you start a service, the system prefers to always keep the process for that service |
| 199 | running. This makes the process very expensive because the RAM used by the service can’t be used by |
| 200 | anything else or paged out. This reduces the number of cached processes that the system can keep in |
| 201 | the LRU cache, making app switching less efficient. It can even lead to thrashing in the system |
| 202 | when memory is tight and the system can’t maintain enough processes to host all the services |
| 203 | currently running.</p> |
| 204 | |
| 205 | <p>The best way to limit the lifespan of your service is to use an {@link |
| 206 | android.app.IntentService}, which finishes |
| 207 | itself 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 |
| 212 | mistakes</strong> an Android app can make. So don’t be greedy by keeping a service for your app |
| 213 | running. Not only will it increase the risk of your app performing poorly due to RAM constraints, |
| 214 | but 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 |
| 220 | release any resources that are used by only your UI. Releasing UI resources at this time can |
| 221 | significantly increase the system's capacity for cached processes, which has a direct impact on the |
| 222 | quality of the user experience.</p> |
| 223 | |
| 224 | <p>To be notified when the user exits your UI, implement the {@link |
| 225 | android.content.ComponentCallbacks2#onTrimMemory onTrimMemory()} callback in your {@link |
| 226 | android.app.Activity} classes. You should use this |
| 227 | method to listen for the {@link android.content.ComponentCallbacks2#TRIM_MEMORY_UI_HIDDEN} level, |
| 228 | which indicates your UI is now hidden from view and you should free resources that only your UI |
| 229 | uses.</p> |
| 230 | |
| 231 | |
| 232 | <p>Notice that your app receives the {@link android.content.ComponentCallbacks2#onTrimMemory |
| 233 | onTrimMemory()} callback with {@link android.content.ComponentCallbacks2#TRIM_MEMORY_UI_HIDDEN} |
| 234 | only when <em>all the UI components</em> of your app process become hidden from the user. |
| 235 | This is distinct |
| 236 | from the {@link android.app.Activity#onStop onStop()} callback, which is called when an {@link |
| 237 | android.app.Activity} instance becomes hidden, which occurs even when the user moves to |
| 238 | another activity in your app. So although you should implement {@link android.app.Activity#onStop |
| 239 | onStop()} to release activity resources such as a network connection or to unregister broadcast |
| 240 | receivers, you usually should not release your UI resources until you receive {@link |
| 241 | android.content.ComponentCallbacks2#onTrimMemory onTrimMemory(TRIM_MEMORY_UI_HIDDEN)}. This ensures |
| 242 | that if the user navigates <em>back</em> from another activity in your app, your UI resources are |
| 243 | still 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 |
| 250 | android.content.ComponentCallbacks2#onTrimMemory onTrimMemory()} callback also tells you when |
| 251 | the overall device memory is getting low. You should respond by further releasing resources based |
| 252 | on the following memory levels delivered by {@link android.content.ComponentCallbacks2#onTrimMemory |
| 253 | onTrimMemory()}:</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 |
| 258 | system 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 |
| 263 | memory so you should release unused resources to improve system performance (which directly |
| 264 | impacts 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 |
| 269 | LRU cache, so you should release all non-critical resources now. If the system cannot reclaim |
| 270 | sufficient amounts of RAM, it will clear all of the LRU cache and begin killing processes that |
| 271 | the 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 |
| 276 | levels 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. |
| 280 | Although your app process is not at a high risk of being killed, the system may already be killing |
| 281 | processes in the LRU cache. You should release resources that are easy to recover so your process |
| 282 | will 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 |
| 287 | system 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 |
| 292 | system does not recover memory now. You should release everything that's not critical to |
| 293 | resuming your app state.</p> |
| 294 | |
| 295 | </li> |
| 296 | </ul> |
| 297 | |
| 298 | <p>Because the {@link android.content.ComponentCallbacks2#onTrimMemory onTrimMemory()} callback was |
| 299 | added in API level 14, you can use the {@link android.content.ComponentCallbacks#onLowMemory()} |
| 300 | callback as a fallback for older versions, which is roughly equivalent to the {@link |
| 301 | android.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, |
| 304 | although it primarily works bottom-up, it does give some consideration to which processes are |
| 305 | consuming more memory and will thus provide the system more memory gain if killed. |
| 306 | So the less memory you consume while in the LRU list overall, the better your chances are |
| 307 | to 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 |
| 314 | system and thus provides a different heap limit for each app. You can call {@link |
| 315 | android.app.ActivityManager#getMemoryClass()} to get an estimate of your app's available heap in |
| 316 | megabytes. 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 |
| 320 | href="{@docRoot}guide/topics/manifest/application-element.html#largeHeap">{@code largeHeap}</a> |
| 321 | attribute to "true" in the manifest <a |
| 322 | href="{@docRoot}guide/topics/manifest/application-element.html">{@code <application>}</a> |
| 323 | tag. If you do so, you can call {@link |
| 324 | android.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 |
| 327 | justify the need to consume more RAM (such as a large photo editing app). <strong>Never request a |
| 328 | large heap simply because you've run out of memory</strong> and you need a quick fix—you |
| 329 | should use it only when you know exactly where all your memory is being allocated and why it must |
| 330 | be retained. Yet, even when you're confident your app can justify the large heap, you should avoid |
| 331 | requesting it to whatever extent possible. Using the extra memory will increasingly be to the |
| 332 | detriment of the overall user experience because garbage collection will take longer and system |
| 333 | performance 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 |
| 336 | devices that have limited RAM, the large heap size may be exactly the same as the regular heap |
| 337 | size. So even if you do request the large heap size, you should call {@link |
| 338 | android.app.ActivityManager#getMemoryClass()} to check the regular heap size and strive to always |
| 339 | stay 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 |
| 345 | screen, scaling it down if the original bitmap is a higher resolution. Keep in mind that an |
| 346 | increase in bitmap resolution results in a corresponding (increase<sup>2</sup>) in memory needed, |
| 347 | because 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 |
| 350 | always appear as the same size in your app heap regardless of the image resolution (the actual |
| 351 | pixel data is stored separately in native memory). This makes it more difficult to debug the bitmap |
| 352 | memory allocation because most heap analysis tools do not see the native allocation. However, |
| 353 | beginning in Android 3.0 (API level 11), the bitmap pixel data is allocated in your app's Dalvik |
| 354 | heap, improving garbage collection and debuggability. So if your app uses bitmaps and you're having |
| 355 | trouble discovering why your app is using some memory on an older device, switch to a device |
| 356 | running Android 3.0 or higher to debug it.</p> |
| 357 | |
| 358 | <p>For more tips about working with bitmaps, read <a |
| 359 | href="{@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 |
| 365 | android.util.SparseArray}, {@link android.util.SparseBooleanArray}, and {@link |
| 366 | android.support.v4.util.LongSparseArray}. The generic {@link java.util.HashMap} |
| 367 | implementation can be quite memory |
| 368 | inefficient because it needs a separate entry object for every mapping. Additionally, the {@link |
| 369 | android.util.SparseArray} classes are more efficient because they avoid the system's need |
| 370 | to <acronym title= |
| 371 | "Automatic conversion from primitive types to object classes (such as int to Integer)" |
| 372 | >autobox</acronym> |
| 373 | the key and sometimes value (which creates yet another object or two per entry). And don't be |
| 374 | afraid 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 |
| 381 | keep this information in mind when you design your app, from start to finish. Often, things on the |
| 382 | surface 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 |
| 385 | avoid 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 |
| 392 | additional entry object that takes 32 bytes (see the previous section about <a |
| 393 | href="#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 |
| 397 | from this overhead. That can leave you in the difficult position of looking at a heap analysis and |
| 398 | realizing 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 |
| 404 | can improve code flexibility and maintenance. However, abstractions come at a significant cost: |
| 405 | generally they require a fair amount more code that needs to be executed, requiring more time and |
| 406 | more RAM for that code to be mapped into memory. So if your abstractions aren't supplying a |
| 407 | significant 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 |
| 413 | buffers</a> are a language-neutral, platform-neutral, extensible mechanism designed by Google for |
| 414 | serializing structured data—think XML, but smaller, faster, and simpler. If you decide to use |
| 415 | protobufs for your data, you should always use nano protobufs in your client-side code. Regular |
| 416 | protobufs generate extremely verbose code, which will cause many kinds of problems in your app: |
| 417 | increased RAM use, significant APK size increase, slower execution, and quickly hitting the DEX |
| 418 | symbol limit.</p> |
| 419 | |
| 420 | <p>For more information, see the "Nano version" section in the <a |
| 421 | href="https://android.googlesource.com/platform/external/protobuf/+/master/java/README.txt" |
| 422 | class="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 |
| 429 | href="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 |
| 431 | attractive because they can simplify the code you write and provide an adaptive environment |
| 432 | that's useful for testing and other configuration changes. However, these frameworks tend to perform |
| 433 | a lot of process initialization by scanning your code for annotations, which can require significant |
| 434 | amounts of your code to be mapped into RAM even though you don't need it. These mapped pages are |
| 435 | allocated into clean memory so Android can drop them, but that won't happen until the pages have |
| 436 | been 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 |
| 442 | for work on a mobile client. At the very least, when you decide to use an external library, you |
| 443 | should assume you are taking on a significant porting and maintenance burden to optimize the |
| 444 | library for mobile. Plan for that work up-front and analyze the library in terms of code size and |
| 445 | RAM 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 |
| 448 | library may do things differently. For example, one library may use nano protobufs while another |
| 449 | uses micro protobufs. Now you have two different protobuf implementations in your app. This can and |
| 450 | will also happen with different implementations of logging, analytics, image loading frameworks, |
| 451 | caching, and all kinds of other things you don't expect. <a |
| 452 | href="{@docRoot}tools/help/proguard.html">ProGuard</a> won't save you here because these |
| 453 | will all be lower-level dependencies that are required by the features for which you want the |
| 454 | library. This becomes especially problematic when you use an {@link android.app.Activity} |
| 455 | subclass from a library (which |
| 456 | will tend to have wide swaths of dependencies), when libraries use reflection (which is common and |
| 457 | means 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 |
| 460 | dozens of other things it does; you don't want to pull in a large amount of code and overhead that |
| 461 | you don't even use. At the end of the day, if there isn't an existing implementation that is a |
| 462 | strong 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 |
| 468 | in other documents listed in <a href="{@docRoot}training/best-performance.html">Best Practices |
| 469 | for Performance</a>. Many of these documents include optimizations tips for CPU performance, but |
| 470 | many of these tips also help optimize your app's memory use, such as by reducing the number of |
| 471 | layout objects required by your UI.</p> |
| 472 | |
| 473 | <p>You should also read about <a href="{@docRoot}tools/debugging/debugging-ui.html">optimizing |
| 474 | your UI</a> with the layout debugging tools and take advantage of |
| 475 | the optimization suggestions provided by the <a |
| 476 | href="{@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, |
| 482 | optimizes, and obfuscates your code by removing unused code and renaming classes, fields, and |
| 483 | methods with semantically obscure names. Using ProGuard can make your code more compact, requiring |
| 484 | fewer 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 |
| 490 | with your final production certificate), then you must run <a |
| 491 | href="{@docRoot}tools/help/zipalign.html">zipalign</a> on it to have it re-aligned. |
| 492 | Failing to do so can cause your app to require significantly more RAM, because things like |
| 493 | resources 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 |
| 496 | are 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 |
| 502 | throughout all stages of its lifecycle. For information about how to analyze your app, read <a |
| 503 | href="{@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 |
| 511 | memory is dividing components of your app into multiple processes. This technique must always be |
| 512 | used carefully and <strong>most apps should not run multiple processes</strong>, as it can easily |
| 513 | increase—rather than decrease—your RAM footprint if done incorrectly. It is primarily |
| 514 | useful to apps that may run significant work in the background as well as the foreground and can |
| 515 | manage those operations separately.</p> |
| 516 | |
| 517 | |
| 518 | <p>An example of when multiple processes may be appropriate is when building a music player that |
| 519 | plays music from a service for long period of time. If |
| 520 | the entire app runs in one process, then many of the allocations performed for its activity UI must |
| 521 | be kept around as long as it is playing music, even if the user is currently in another app and the |
| 522 | service is controlling the playback. An app like this may be split into two process: one for its |
| 523 | UI, 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 |
| 527 | for each component in the manifest file. For example, you can specify that your service should run |
| 528 | in 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 | <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 |
| 537 | your app.</p> |
| 538 | |
| 539 | <p>Before you decide to create a new process, you need to understand the memory implications. |
| 540 | To illustrate the consequences of each process, consider that an empty process doing basically |
| 541 | nothing has an extra memory footprint of about 1.4MB, as shown by the memory information |
| 542 | dump below.</p> |
| 543 | |
| 544 | <pre class="no-pretty-print"> |
| 545 | adb 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 |
| 565 | in <a href="{@docRoot}tools/debugging/debugging-memory.html#ViewingAllocations">Investigating |
| 566 | Your RAM Usage</a>. The key data here is the <em>Private Dirty</em> and <em>Private |
| 567 | Clean</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), |
| 569 | and 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 |
| 572 | grow as you start doing work in that process. For |
| 573 | example, here is the memory use of a process that is created only to show an activity with some |
| 574 | text 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 |
| 597 | leads to an important conclusion: If you are going to split your app into multiple processes, only |
| 598 | one process should be responsible for UI. Other processes should avoid any UI, as this will quickly |
| 599 | increase the RAM required by the process (especially once you start loading bitmap assets and other |
| 600 | resources). 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 |
| 603 | code as lean as possible, because any unnecessary RAM overhead for common implementations are now |
| 604 | replicated in each process. For example, if you are using enums (though <a |
| 605 | href="#Overhead">you should not use enums</a>), all of |
| 606 | the RAM needed to create and initialize those constants is duplicated in each process, and any |
| 607 | abstractions 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, |
| 610 | if your app has a content provider that you have running in the default process which also hosts |
| 611 | your UI, then code in a background process that uses that content provider will also require that |
| 612 | your UI process remain in RAM. If your goal is to have a background process that can run |
| 613 | independently of a heavy-weight UI process, it can't have dependencies on content providers or |
| 614 | services 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"> |
| 631 | adb shell dumpsys activity |
| 632 | </pre> |
| 633 | |
| 634 | <p>This dumps various information about the Activity Manager's state, ending with a list of all |
| 635 | processes in their memory management order, including the reason each process is at its given |
| 636 | level. For example, below is a dump with the Music app in the foreground.</p> |
| 637 | |
| 638 | <pre class="no-pretty-print"> |
| 639 | ACTIVITY 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 |
| 681 | platform 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 |
| 688 | class 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 |
| 691 | running.</li> |
| 692 | |
| 693 | <li>Dependent process: This shows how the Music app is using two processes. Its UI process has a |
| 694 | dependency on the "main" process (through a content provider). So while the UI process is in use, |
| 695 | the main process must also be kept around. This means the app's memory footprint is actually the |
| 696 | sum of both processes. You will have this kind of connection on a content provider any time you |
| 697 | have 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 |
| 700 | generally means that it is either something the user can literally see (such as a process hosting a |
| 701 | paused but visible activity that is behind a non-full-screen dialog) or is something the user might |
| 702 | notice if the process disappeared (such as a foreground service playing music). You should be |
| 703 | certain that any process you have running at the "visible" level is indeed critical to the user, |
| 704 | because 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 |
| 707 | list is the start of less-critical processes, which the system has some freedom to kill if RAM is |
| 708 | needed elsewhere. These services are still quite expensive because they can be killed only |
| 709 | temporarily 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 |
| 712 | prevent it from being killed as much as possible. Killing this process is much more damaging to the |
| 713 | user experience than killing other cached processes, because so much user interaction goes through |
| 714 | home.</li> |
| 715 | |
| 716 | <li>Secondary service processes: These are services that have been running for a relatively long time |
| 717 | and 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 |
| 720 | switching and component launching. These processes are not required and the system will kill them |
| 721 | as needed to reclaim memory. You will often see a process hosting a running service here—this is |
| 722 | part of a platform policy of allowing very long-running services to drop down into the LRU list and |
| 723 | eventually be killed. If the service should continue running (as defined by the {@link |
| 724 | android.app.Service#onStartCommand onStartCommand()} return value, such as {@link |
| 725 | android.app.Service#START_STICKY}), the the system eventually restarts it. This avoids issues with |
| 726 | such services having memory leaks that over time reduce the number of regular cached processes that |
| 727 | can be kept.</li> |
| 728 | |
| 729 | </ol> |
| 730 | |
| 731 | <p>This numbered list of processes is essentially the LRU list of processes that the framework |
| 732 | provides to the kernel to help it determine which processes it should kill as it needs more RAM. |
| 733 | The kernel's out of memory killer will generally begin from the bottom of this list, killing the |
| 734 | last process and working its way up. It may not do it in exactly this order, as it can also take |
| 735 | into 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 |
| 738 | your app's state—use <code>adb shell dumpsys activity -h</code> for help on its use.</p> |
| 739 | |
| 740 | --> |