Home | History | Annotate | Download | only in performance
      1 page.title=Manage Your App's Memory
      2 page.tags=ram,low memory,OutOfMemoryError,onTrimMemory
      3 
      4 @jd:body
      5 
      6 <div id="qv-wrapper">
      7 <div id="qv">
      8 
      9 <h2>In this document</h2>
     10 <ol>
     11   <li><a href="#monitor">Monitor Available Memory and Memory Usage</a>
     12     <ul>
     13       <li><a href="#AnalyzeRam">Tools for analyzing RAM usage</a></li>
     14       <li><a href="#release">Release memory in response to events</a></li>
     15       <li><a href="#CheckHowMuchMemory">Check how much memory you should use</a></li>
     16     </ul>
     17   </li>
     18   <li><a href="#code">Use More Efficient Code Constructs</a>
     19     <ul>
     20       <li><a href="#Services">Use services sparingly</a></li>
     21       <li><a href="#DataContainers">Use optimized data containers</a></li>
     22       <li><a href="#Abstractions">Be careful with code abstractions</a></li>
     23       <li><a href="#NanoProto">Use nano protobufs for serialized data</a></li>
     24       <li><a href="#churn">Avoid memory churn</a></li>
     25     </ul>
     26   </li>
     27   <li><a href="#remove">Remove Memory-Intensive Resources and Libraries</a>
     28     <ul>
     29       <li><a href="#reduce">Reduce overall APK size</a></li>
     30       <li><a href="#DependencyInjection">Avoid dependency injection frameworks</a></li>
     31       <li><a href="#ExternalLibs">Be careful about using external libraries</a></li>
     32     </ul>
     33   </li>
     34 </ol>
     35 <h2>See Also</h2>
     36 <ul>
     37   <li><a href="{@docRoot}training/articles/memory-overview.html">Overview of Android Memory Management</a>
     38   </li>
     39   <li><a href="{@docRoot}studio/profile/investigate-ram.html">Investigating Your RAM Usage</a>
     40   </li>
     41   <li><a href="{@docRoot}topic/performance/reduce-apk-size.html">Reduce APK Size</a></li>
     42 </ul>
     43 
     44 </div>
     45 </div>
     46 
     47 <!-- INTRO #################################################### -->
     48 
     49 <p>
     50   Random-access memory (RAM) is a valuable
     51   resource in any software development environment, but
     52   it's even more valuable on a mobile operating system
     53   where physical memory is often constrained.
     54   Although both the Android Runtime (ART) and Dalvik virtual machine perform
     55   routine garbage collection, this does not mean you can ignore
     56   when and where your app allocates and releases memory.
     57   You still need to avoid
     58   introducing memory leaks, usually caused by holding onto
     59   object references in static member variables, and
     60   release any {@link java.lang.ref.Reference} objects at the appropriate
     61   time as defined by
     62   lifecycle callbacks.
     63 </p>
     64 
     65 <p>
     66   This page explains how you can
     67   proactively reduce memory usage within your app.
     68   For more information about general
     69   practices to clean up your resources when programming in Java,
     70   refer to other books or online
     71   documentation about managing resource references.
     72   If youre looking for information about how to
     73   analyze memory in a running app, read
     74   <a href="#AnalyzeRam">Tools for analyzing RAM usage</a>.
     75   For more detailed information about how the Android Runtime and Dalvik
     76   virtual machine manage memory, see the
     77   <a href="{@docRoot}training/articles/memory-overview.html">Overview of Android Memory Management</a>.
     78 </p>
     79 
     80 <!-- Section 1 #################################################### -->
     81 
     82 <h2 id="monitor">Monitor Available Memory and Memory Usage</h2>
     83 
     84 <p>
     85   The Android framework, Android Studio, and Android SDK
     86   can help you analyze and adjust your app's memory usage.
     87   The Android framework
     88   exposes several APIs that allow your app to reduce its memory usage
     89   dynamically during runtime. Android Studio and the Android SDK
     90   contain several tools  that allow you to investigate how your
     91   app uses memory.
     92 </p>
     93 
     94 <!-- Section 1.1 #################################################### -->
     95 
     96 <h3 id="AnalyzeRam">Tools for analyzing RAM usage</h3>
     97 
     98 <p>
     99   Before you can fix the memory usage problems in your app, you first need
    100   to find them. Android Studio and the Android SDK include several tools
    101   for analyzing memory usage in your app:
    102 </p>
    103 
    104 <ol>
    105   <li>
    106     The Device Monitor has a Dalvik Debug Monitor Server (DDMS) tool that allows
    107     you to inspect memory allocation within your app process.
    108     You can use this information to understand how your
    109     app uses memory overall. For example, you can force a garbage collection
    110     event and then view the types of objects that remain in memory. You can
    111     use this information to identify operations or actions within your app
    112     that allocate or leave excessive amounts of objects in memory.
    113 
    114     <p>For more information about how to use the DDMS tool, see
    115       <a href="/studio/profile/ddms.html">Using DDMS</a>.
    116     </p>
    117   </li>
    118 
    119   <li>
    120     The Memory Monitor in Android Studio shows you how your app allocates
    121     memory over the course of a single session.
    122     The tool shows a graph of available
    123     and allocated Java memory over time, including garbage collection events.
    124     You can also initiate garbage collection events and take a snapshot of
    125     the Java heap while your app runs. The output from the Memory Monitor tool
    126     can help you identify points when your app experiences excessive garbage
    127     collection events, leading to app slowness.
    128     <p>
    129       For more information about how to use Memory Monitor tool, see
    130       <a href="{@docRoot}tools/debugging/debugging-memory.html#ViewHeap">Viewing Heap Updates</a>.
    131     </p>
    132   </li>
    133 
    134   <li>
    135     Garbage collection events also show up in the Traceview viewer. Traceview
    136     allows you to view trace log files as both a timeline and as a profile
    137     of what happened within a method. You can use this tool to determine
    138     what code was executing when a garbage collection event occurred.
    139     <p>
    140       For more information about how to use the Traceview viewer, see
    141       <a href="https://developer.android.com/studio/profile/traceview.html">Profiling with Traceview and dmtracedump</a>.
    142     </p>
    143   </li>
    144 
    145   <li>
    146     The Allocation Tracker tool in Android Studio gives you a detailed look
    147     at how your app allocates memory.
    148     The Allocation Tracker records an app's memory allocations and lists
    149     all allocated objects within the profiling snapshot. You can use this
    150     tool to track down parts of your code that allocate too many objects.
    151 
    152     <p>
    153       For more information about how to use the Allocation Tracker tool, see
    154       <a href="{docRoot}studio/profile/allocation-tracker-walkthru.html">Allocation Tracker Walkthrough</a>.
    155     </p>
    156   </li>
    157 
    158 </ol>
    159 
    160 <!-- Section 1.2 #################################################### -->
    161 
    162 <h3 id="release">Release memory in response to events</h3>
    163 
    164 <p>
    165   An Android device can run with varying amounts of free memory
    166   depending on the physical amount of RAM on the device and how the user
    167   operates it. The system broadcasts signals to indicate when it is under
    168   memory pressure, and apps should listen for these signals and adjust
    169   their memory usage as appropriate.
    170 </p>
    171 
    172 </p>
    173   You can use the {@link android.content.ComponentCallbacks2} API
    174   to listen for these signals and then adjust your memory
    175   usage in response to app lifecycle
    176   or device events. The
    177   {@link android.content.ComponentCallbacks2#onTrimMemory onTrimMemory()}
    178   method allows your app to listen for memory related events when the app runs
    179   in the foreground (is visible) and when it runs in the background.
    180 </p>
    181 
    182 <p>
    183   To listen for these events, implement the {@link
    184   android.content.ComponentCallbacks2#onTrimMemory onTrimMemory()}
    185   callback in your {@link android.app.Activity}
    186   classes, as shown in the following code snippet.
    187 </p>
    188 
    189 <pre class="prettyprint">
    190 import android.content.ComponentCallbacks2;
    191 // Other import statements ...
    192 
    193 public class MainActivity extends AppCompatActivity
    194     implements ComponentCallbacks2 {
    195 
    196     // Other activity code ...
    197 
    198     /**
    199      * Release memory when the UI becomes hidden or when system resources become low.
    200      * @param level the memory-related event that was raised.
    201      */
    202     public void onTrimMemory(int level) {
    203 
    204         // Determine which lifecycle or system event was raised.
    205         switch (level) {
    206 
    207             case ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN:
    208 
    209                 /*
    210                    Release any UI objects that currently hold memory.
    211 
    212                    The user interface has moved to the background.
    213                 */
    214 
    215                 break;
    216 
    217             case ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE:
    218             case ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW:
    219             case ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL:
    220 
    221                 /*
    222                    Release any memory that your app doesn't need to run.
    223 
    224                    The device is running low on memory while the app is running.
    225                    The event raised indicates the severity of the memory-related event.
    226                    If the event is TRIM_MEMORY_RUNNING_CRITICAL, then the system will
    227                    begin killing background processes.
    228                 */
    229 
    230                 break;
    231 
    232             case ComponentCallbacks2.TRIM_MEMORY_BACKGROUND:
    233             case ComponentCallbacks2.TRIM_MEMORY_MODERATE:
    234             case ComponentCallbacks2.TRIM_MEMORY_COMPLETE:
    235 
    236                 /*
    237                    Release as much memory as the process can.
    238 
    239                    The app is on the LRU list and the system is running low on memory.
    240                    The event raised indicates where the app sits within the LRU list.
    241                    If the event is TRIM_MEMORY_COMPLETE, the process will be one of
    242                    the first to be terminated.
    243                 */
    244 
    245                 break;
    246 
    247             default:
    248                 /*
    249                   Release any non-critical data structures.
    250 
    251                   The app received an unrecognized memory level value
    252                   from the system. Treat this as a generic low-memory message.
    253                 */
    254                 break;
    255         }
    256     }
    257 }
    258 </pre>
    259 
    260 <p>
    261   The
    262   {@link android.content.ComponentCallbacks2#onTrimMemory onTrimMemory()}
    263   callback was added in Android 4.0 (API level 14). For earlier versions,
    264   you can use the
    265   {@link android.content.ComponentCallbacks#onLowMemory()}
    266   callback as a fallback for older versions, which is roughly equivalent to the
    267   {@link android.content.ComponentCallbacks2#TRIM_MEMORY_COMPLETE} event.
    268 </p>
    269 
    270 <!-- Section 1.3 #################################################### -->
    271 
    272 <h3 id="CheckHowMuchMemory">Check how much memory you should use</h3>
    273 
    274 <p>
    275   To allow multiple running processes, Android sets a hard limit
    276   on the heap size alloted for each app. The exact heap size limit varies
    277   between devices based on how much RAM the device
    278   has available overall. If your app has reached the heap capacity and
    279   tries to allocate more
    280   memory, the system throws an {@link java.lang.OutOfMemoryError}.
    281 </p>
    282 
    283 <p>
    284   To avoid running out of memory, you can to query the system to determine
    285   how much heap space you have available on the current device.
    286   You can query the system for this figure by calling
    287   {@link android.app.ActivityManager#getMemoryInfo(android.app.ActivityManager.MemoryInfo) getMemoryInfo()}.
    288   This returns an
    289   {@link android.app.ActivityManager.MemoryInfo } object that provides
    290   information about the device's
    291   current memory status, including available memory, total memory, and
    292   the memory threshold&mdash;the memory level below which the system begins
    293   to kill processes. The
    294   {@link android.app.ActivityManager.MemoryInfo } class also exposes a simple
    295   boolean field,
    296   {@link android.app.ActivityManager.MemoryInfo#lowMemory }
    297   that tells you whether the device is running low on memory.
    298 </p>
    299 
    300 <p>
    301   The following code snippet shows an example of how you can use the
    302   {@link android.app.ActivityManager#getMemoryInfo(android.app.ActivityManager.MemoryInfo) getMemoryInfo()}.
    303   method in your application.
    304 </p>
    305 
    306 <pre class="prettyprint">
    307 public void doSomethingMemoryIntensive() {
    308 
    309     // Before doing something that requires a lot of memory,
    310     // check to see whether the device is in a low memory state.
    311     ActivityManager.MemoryInfo memoryInfo = getAvailableMemory();
    312 
    313     if (!memoryInfo.lowMemory) {
    314         // Do memory intensive work ...
    315     }
    316 }
    317 
    318 // Get a MemoryInfo object for the device's current memory status.
    319 private ActivityManager.MemoryInfo getAvailableMemory() {
    320     ActivityManager activityManager = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
    321     ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
    322     activityManager.getMemoryInfo(memoryInfo);
    323     return memoryInfo;
    324 }
    325 </pre>
    326 
    327 <!-- Section 2 #################################################### -->
    328 
    329 <h2 id="code">Use More Memory-Efficient Code Constructs</h2>
    330 
    331 <p>
    332   Some Android features, Java classes, and code constructs tend to
    333   use more memory than others. You can minimize how
    334   much memory your app uses by choosing more efficient alternatives in
    335   your code.
    336 </p>
    337 
    338 <!-- Section 2.1 #################################################### -->
    339 
    340 <h3 id="Services">Use services sparingly</h3>
    341 
    342 <p>
    343   Leaving a service running when its not needed is
    344   <strong>one of the worst memory-management
    345   mistakes</strong> an Android app can make. If your app needs a
    346   <a href="{@docRoot}guide/components/services.html">service</a>
    347   to perform work in the background, do not keep it running unless
    348   it needs to run a job. Remember to stop your service when it has completed
    349   its task. Otherwise, you can inadvertently cause a memory leak.
    350 </p>
    351 
    352 <p>
    353   When you start a service, the system prefers to always keep the process
    354   for that service running. This behavior
    355   makes services processes very expensive
    356   because the RAM used by a service remains unavailable to other processes.
    357   This reduces the number of cached processes that the system can keep in
    358   the LRU cache, making app switching less efficient. It can even lead to
    359   thrashing in the system when memory is tight and the system cant
    360   maintain enough processes to host all the services currently running.
    361 </p>
    362 
    363 <p>
    364   You should generally avoid use of persistent services because of
    365   the on-going demands they place on available memory. Instead, we
    366   recommend that you use an alternative implementation
    367   such as {@link android.app.job.JobScheduler}. For more information about
    368   how to use {@link android.app.job.JobScheduler} to schedule background
    369   processes, see
    370   <a href="/topic/performance/background-optimization.html">Background Optimizations</a>.
    371 <p>
    372   If you must use a service, the
    373   best way to limit the lifespan of your service is to use an {@link
    374   android.app.IntentService}, which finishes
    375   itself as soon as it's done handling the intent that started it.
    376   For more information, read
    377   <a href="{@docRoot}training/run-background-service/index.html">Running in a Background Service</a>.
    378 </p>
    379 
    380 <!-- Section 2.2 #################################################### -->
    381 
    382 <h3 id="DataContainers">Use optimized data containers</h3>
    383 
    384 <p>
    385   Some of the classes provided by the programming language are not optimized for
    386   use on mobile devices. For example, the generic
    387   {@link java.util.HashMap} implementation can be quite memory
    388   inefficient because it needs a separate entry object for every mapping.
    389 </p>
    390 
    391 <p>
    392   The Android framework includes several optimized data containers, including
    393   {@link android.util.SparseArray}, {@link android.util.SparseBooleanArray},
    394   and {@link android.support.v4.util.LongSparseArray}.
    395   For example, the {@link android.util.SparseArray} classes are more
    396   efficient because they avoid the system's need to
    397   <acronym title="Automatic conversion from primitive types to object classes (such as int to Integer)">autobox</acronym>
    398   the key and sometimes value (which creates yet another object or
    399   two per entry).
    400 </p>
    401 
    402 <p>
    403   If necessary, you can always switch to raw arrays for a really lean data
    404   structure.
    405 </p>
    406 
    407 <!-- Section 2.3 #################################################### -->
    408 
    409 <h3 id="Abstractions">Be careful with code abstractions</h3>
    410 
    411 <p>
    412   Developers often use abstractions simply as a good programming practice,
    413   because abstractions can improve code flexibility and maintenance.
    414   However, abstractions come at a significant cost:
    415   generally they require a fair amount more code that
    416   needs to be executed, requiring more time and
    417   more RAM for that code to be mapped into memory.
    418   So if your abstractions aren't supplying a
    419   significant benefit, you should avoid them.
    420 </p>
    421 
    422 <p>
    423   For example, enums often require more than twice as much memory as static
    424   constants. You should strictly avoid using enums on Android.
    425 </p>
    426 
    427 <!-- Section 2.4 #################################################### -->
    428 
    429 <h3 id="NanoProto">Use nano protobufs for serialized data</h3>
    430 
    431 <p>
    432   <a href="https://developers.google.com/protocol-buffers/docs/overview">Protocol buffers</a>
    433   are a language-neutral, platform-neutral, extensible mechanism
    434   designed by Google for serializing structured data&mdash;similar to XML, but
    435   smaller, faster, and simpler. If you decide to use
    436   protobufs for your data, you should always use nano protobufs in your
    437   client-side code. Regular protobufs generate extremely verbose code, which
    438   can cause many kinds of problems in your app such as
    439   increased RAM use, significant APK size increase, and slower execution.
    440 </p>
    441 
    442 <p>
    443   For more information, see the "Nano version" section in the
    444   <a href="https://android.googlesource.com/platform/external/protobuf/+/master/java/README.txt"
    445 class="external-link">protobuf readme</a>.
    446 </p>
    447 
    448 <!-- Section 2.5 #################################################### -->
    449 
    450 <h3 id="churn">Avoid memory churn</h3>
    451 
    452 <p>
    453   As mentioned previously, garbage collections events don't normally affect
    454   your app's performance. However, many garbage collection events that occur
    455   over a short period of time can quickly eat up your frame time. The more time
    456   that the system spends on garbage collection, the less time it has to do
    457   other stuff like rendering or streaming audio.
    458 </p>
    459 
    460 <p>
    461   Often, <em>memory churn</em> can cause a large number of
    462   garbage collection events to occur. In practice, memory churn describes the
    463   number of allocated temporary objects that occur in a given amount of time.
    464 </p>
    465 
    466 <p>
    467   For example, you might allocate multiple temporary objects within a
    468   <code>for</code> loop. Or you might create new
    469   {@link android.graphics.Paint} or {@link android.graphics.Bitmap}
    470   objects inside the
    471   {@link android.view.View#onDraw(android.graphics.Canvas) onDraw()}
    472   function of a view.
    473   In both cases, the app creates a lot of objects quickly at high volume.
    474   These can quickly consume all the available memory in the young generation,
    475   forcing a garbage collection event to occur.
    476 </p>
    477 
    478 <p>
    479   Of course, you need to find the places in your code where
    480   the memory churn is high before you can fix them. Use the tools discussed in
    481   <a href="#AnalyzeRam">Analyze your RAM usage</a>
    482 </p>
    483 
    484 <p>
    485   Once you identify the problem areas in your code, try to reduce the number of
    486   allocations within performance critical areas. Consider moving things out of
    487   inner loops or perhaps moving them into a
    488   <a href="https://en.wikipedia.org/wiki/Factory_method_pattern" class="external-link">Factory</a>
    489   based allocation structure.
    490 </p>
    491 
    492 <!-- Section 3 #################################################### -->
    493 
    494 <h2 id="remove">Remove Memory-Intensive Resources and Libraries</h2>
    495 
    496 <p>
    497   Some resources and libraries within your code can gobble up memory without
    498   you knowing it. Overall size of your APK, including third-party libraries
    499   or embedded resources, can affect how much memory your app consumes. You can
    500   improve your app's memory consumption by removing any redundant, unnecessary,
    501   or bloated components, resources, or libraries from your code.
    502 </p>
    503 
    504 <!-- Section 3.1 #################################################### -->
    505 
    506 <h3 id="reduce">Reduce overall APK size</h3>
    507 
    508 <p>
    509   You can significantly reduce your app's memory usage by reducing the overall
    510   size of your app. Bitmap size, resources, animation frames, and third-party
    511   libraries can all contribute to the size of your APK.
    512   Android Studio and the Android SDK provide multiple tools
    513   to help you reduce the size of your resources and external dependencies.
    514 </p>
    515 
    516 <p>
    517   For more information about how to reduce your overall APK size, see
    518   <a href="{@docRoot}topic/performance/reduce-apk-size.html">Reduce APK Size</a>.
    519 </p>
    520 
    521 <!-- Section 3.2 #################################################### -->
    522 
    523 <h3 id="DependencyInjection">Use caution with dependency injection frameworks</h3>
    524 
    525 <p>
    526   Dependency injection framework such as
    527   <a href="https://code.google.com/p/google-guice/" class="external-link">Guice</a>
    528   or
    529   <a href="https://github.com/roboguice/roboguice" class="external-link">RoboGuice</a>
    530   can simplify the code you write and provide an adaptive environment
    531   that's useful for testing and other configuration changes. However, dependency
    532   frameworks aren't always optimized for mobile devices.
    533 </p>
    534 
    535 <p>
    536   For example, these frameworks tend to initialize processes by
    537   scanning your code for annotations. This which can require significant
    538   amounts of your code to be mapped into RAM unnecessarily. The system
    539   allocates these mapped pages into clean memory so Android can drop them; yet
    540   that can't happen until the pages have remained in memory for a long period
    541   of time.
    542  </p>
    543 
    544 <p>
    545   If you need to use a dependency injection framework in your app, consider
    546   using
    547   <a class="external-link" href="http://google.github.io/dagger/">Dagger</a>
    548   instead. For example, Dagger does not use reflection to scan your app's code.
    549   Dagger's strict implementation means that it can be used in Android apps
    550   without needlessly increasing memory usage.
    551 </p>
    552 
    553 <!-- Section 3.3 #################################################### -->
    554 
    555 <h3 id="ExternalLibs">Be careful about using external libraries</h3>
    556 
    557 <p>
    558   External library code is often not written for mobile environments and
    559   can be inefficient when used
    560   for work on a mobile client. When you decide to use an
    561   external library, you may need to optimize that library for mobile devices.
    562   Plan for that work up-front and analyze the library in terms of code size and
    563   RAM footprint before deciding to use it at all.
    564 </p>
    565 
    566 <p>
    567   Even some mobile-optimized libraries can cause problems due to differing
    568   implementations. For example, one library may use nano protobufs
    569   while another uses micro protobufs, resulting in two different protobuf
    570   implementations in your app. This can happen with different
    571   implementations of logging, analytics, image loading frameworks,
    572   caching, and many other things you don't expect.
    573 </p>
    574 
    575 <p>
    576   Although <a href="{@docRoot}tools/help/proguard.html">ProGuard</a> can
    577   help to remove APIs and resources with the right flags, it can't remove a
    578   library's large internal dependencies. The features that you want in these
    579   libraries may require lower-level dependencies. This becomes especially
    580   problematic when you use an {@link android.app.Activity } subclass from a
    581   library (which will tend to have wide swaths of dependencies),
    582   when libraries use reflection (which is common and means you need to spend a
    583   lot of time manually tweaking ProGuard to get it to work), and so on.
    584 </p>
    585 
    586 <p>
    587   Also avoid using a shared library for just one or two features out of dozens.
    588   You don't want to pull in a large amount of code and overhead that
    589   you don't even use. When you consider whether to use a library, look for
    590   an implementation that strongly matches what you need. Otherwise, you might
    591   decide to create your own implementation.
    592 </p>
    593 
    594