| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 1 | page.title=Investigating Your RAM Usage |
| Joe Fernandez | 33baa5a | 2013-11-14 11:41:19 -0800 | [diff] [blame] | 2 | page.tags=memory,OutOfMemoryError |
| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 3 | @jd:body |
| 4 | |
| 5 | <div id="qv-wrapper"> |
| 6 | <div id="qv"> |
| 7 | <h2>In this document</h2> |
| 8 | <ol> |
| 9 | <li><a href="#LogMessages">Interpreting Log Messages</a></li> |
| 10 | <li><a href="#ViewHeap">Viewing Heap Updates</a></li> |
| 11 | <li><a href="#TrackAllocations">Tracking Allocations</a></li> |
| 12 | <li><a href="#ViewingAllocations">Viewing Overall Memory Allocations</a></li> |
| 13 | <li><a href="#HeapDump">Capturing a Heap Dump</a></li> |
| 14 | <li><a href="#TriggerLeaks">Triggering Memory Leaks</a></li> |
| 15 | </ol> |
| 16 | <h2>See Also</h2> |
| 17 | <ul> |
| 18 | <li><a href="{@docRoot}training/articles/memory.html">Managing Your App's Memory</a></li> |
| 19 | </ul> |
| 20 | </div> |
| 21 | </div> |
| 22 | |
| 23 | |
| 24 | |
| 25 | |
| 26 | <p>Because Android is designed for mobile devices, you should always be careful about how much |
| Rich Slogar | f6d03e5 | 2015-07-07 11:40:47 -0700 | [diff] [blame] | 27 | random-access memory (RAM) your app uses. Although Dalvik and ART perform |
| 28 | routine garbage collection (GC), this doesn’t mean you can ignore when and where your app allocates and |
| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 29 | releases memory. In order to provide a stable user experience that allows the system to quickly |
| Rich Slogar | f6d03e5 | 2015-07-07 11:40:47 -0700 | [diff] [blame] | 30 | switch between apps, it is important that your app does not needlessly consume memory when the user |
| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 31 | is not interacting with it.</p> |
| 32 | |
| 33 | <p>Even if you follow all the best practices for <a href="{@docRoot}training/articles/memory.html" |
| 34 | >Managing Your App Memory</a> during |
| 35 | development (which you should), you still might leak objects or introduce other memory bugs. The |
| Rich Slogar | f6d03e5 | 2015-07-07 11:40:47 -0700 | [diff] [blame] | 36 | only way to be certain your app is using as little memory as possible is to analyze your app’s |
| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 37 | memory usage with tools. This guide shows you how to do that.</p> |
| 38 | |
| 39 | |
| 40 | <h2 id="LogMessages">Interpreting Log Messages</h2> |
| 41 | |
| Rich Slogar | f6d03e5 | 2015-07-07 11:40:47 -0700 | [diff] [blame] | 42 | <p>The simplest place to begin investigating your app’s memory usage is the runtime log messages. |
| Mathieu Chartier | d92c6bde | 2015-03-23 15:58:11 -0700 | [diff] [blame] | 43 | Sometimes when a GC occurs, a message is printed to |
| 44 | <a href="{@docRoot}tools/help/logcat.html">logcat</a>. The logcat output is also available in the |
| 45 | Device Monitor or directly in IDEs such as Eclipse and Android Studio.</p> |
| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 46 | |
| Mathieu Chartier | d92c6bde | 2015-03-23 15:58:11 -0700 | [diff] [blame] | 47 | <h3 id="DalvikLogMessages">Dalvik Log Messages</h3> |
| 48 | |
| 49 | <p>In Dalvik (but not ART), every GC prints the following information to logcat:</p> |
| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 50 | |
| 51 | <pre class="no-pretty-print"> |
| 52 | D/dalvikvm: <GC_Reason> <Amount_freed>, <Heap_stats>, <External_memory_stats>, <Pause_time> |
| 53 | </pre> |
| 54 | |
| Mathieu Chartier | d92c6bde | 2015-03-23 15:58:11 -0700 | [diff] [blame] | 55 | <p>Example:</p> |
| 56 | |
| 57 | <pre class="no-pretty-print"> |
| 58 | D/dalvikvm( 9050): GC_CONCURRENT freed 2049K, 65% free 3571K/9991K, external 4703K/5261K, paused 2ms+2ms |
| 59 | </pre> |
| 60 | |
| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 61 | <dl> |
| 62 | <dt>GC Reason</dt> |
| 63 | <dd> |
| Mathieu Chartier | d92c6bde | 2015-03-23 15:58:11 -0700 | [diff] [blame] | 64 | What triggered the GC and what kind of collection it is. Reasons that may appear |
| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 65 | include: |
| 66 | <dl> |
| 67 | <dt><code>GC_CONCURRENT</code></dt> |
| Mathieu Chartier | d92c6bde | 2015-03-23 15:58:11 -0700 | [diff] [blame] | 68 | <dd>A concurrent GC that frees up memory as your heap begins to fill up.</dd> |
| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 69 | |
| 70 | <dt><code>GC_FOR_MALLOC</code></dt> |
| Rich Slogar | f6d03e5 | 2015-07-07 11:40:47 -0700 | [diff] [blame] | 71 | <dd>A GC caused because your app attempted to allocate memory when your heap was |
| 72 | already full, so the system had to stop your app and reclaim memory.</dd> |
| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 73 | |
| 74 | <dt><code>GC_HPROF_DUMP_HEAP</code></dt> |
| Mathieu Chartier | d92c6bde | 2015-03-23 15:58:11 -0700 | [diff] [blame] | 75 | <dd>A GC that occurs when you request to create an HPROF file to analyze your heap.</dd> |
| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 76 | |
| 77 | <dt><code>GC_EXPLICIT</code> |
| Mathieu Chartier | d92c6bde | 2015-03-23 15:58:11 -0700 | [diff] [blame] | 78 | <dd>An explicit GC, such as when you call {@link java.lang.System#gc()} (which you |
| 79 | should avoid calling and instead trust the GC to run when needed).</dd> |
| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 80 | |
| 81 | <dt><code>GC_EXTERNAL_ALLOC</code></dt> |
| 82 | <dd>This happens only on API level 10 and lower (newer versions allocate everything in the Dalvik |
| Mathieu Chartier | d92c6bde | 2015-03-23 15:58:11 -0700 | [diff] [blame] | 83 | heap). A GC for externally allocated memory (such as the pixel data stored in |
| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 84 | native memory or NIO byte buffers).</dd> |
| 85 | </dl> |
| 86 | </dd> |
| 87 | |
| 88 | <dt>Amount freed</dt> |
| Mathieu Chartier | d92c6bde | 2015-03-23 15:58:11 -0700 | [diff] [blame] | 89 | <dd>The amount of memory reclaimed from this GC.</dd> |
| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 90 | |
| 91 | <dt>Heap stats</dt> |
| Mathieu Chartier | d92c6bde | 2015-03-23 15:58:11 -0700 | [diff] [blame] | 92 | <dd>Percentage free of the heap and (number of live objects)/(total heap size).</dd> |
| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 93 | |
| 94 | <dt>External memory stats</dt> |
| 95 | <dd>Externally allocated memory on API level 10 and lower (amount of allocated memory) / (limit at |
| 96 | which collection will occur).</dd> |
| 97 | |
| 98 | <dt>Pause time</dt> |
| 99 | <dd>Larger heaps will have larger pause times. Concurrent pause times show two pauses: one at the |
| 100 | beginning of the collection and another near the end.</dd> |
| 101 | </dl> |
| 102 | |
| Mathieu Chartier | d92c6bde | 2015-03-23 15:58:11 -0700 | [diff] [blame] | 103 | <p>As these log messages accumulate, look out for increases in the heap stats (the |
| 104 | {@code 3571K/9991K} value in the above example). If this value continues to increase, you may have |
| 105 | a memory leak.</p> |
| 106 | |
| 107 | |
| 108 | <h3 id="ARTLogMessages">ART Log Messages</h3> |
| 109 | |
| Rich Slogar | f6d03e5 | 2015-07-07 11:40:47 -0700 | [diff] [blame] | 110 | <p>Unlike Dalvik, ART doesn't log messqages for GCs that were not explicitly requested. GCs are only |
| Mathieu Chartier | d92c6bde | 2015-03-23 15:58:11 -0700 | [diff] [blame] | 111 | printed when they are they are deemed slow. More precisely, if the GC pause exceeds than 5ms or |
| Rich Slogar | f6d03e5 | 2015-07-07 11:40:47 -0700 | [diff] [blame] | 112 | the GC duration exceeds 100ms. If the app is not in a pause perceptible process state, |
| Mathieu Chartier | d92c6bde | 2015-03-23 15:58:11 -0700 | [diff] [blame] | 113 | then none of its GCs are deemed slow. Explicit GCs are always logged.</p> |
| 114 | |
| 115 | <p>ART includes the following information in its garbage collection log messages:</p> |
| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 116 | |
| 117 | <pre class="no-pretty-print"> |
| Mathieu Chartier | d92c6bde | 2015-03-23 15:58:11 -0700 | [diff] [blame] | 118 | I/art: <GC_Reason> <GC_Name> <Objects_freed>(<Size_freed>) AllocSpace Objects, <Large_objects_freed>(<Large_object_size_freed>) <Heap_stats> LOS objects, <Pause_time(s)> |
| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 119 | </pre> |
| 120 | |
| Mathieu Chartier | d92c6bde | 2015-03-23 15:58:11 -0700 | [diff] [blame] | 121 | <p>Example:</p> |
| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 122 | |
| Mathieu Chartier | d92c6bde | 2015-03-23 15:58:11 -0700 | [diff] [blame] | 123 | <pre class="no-pretty-print"> |
| 124 | I/art : Explicit concurrent mark sweep GC freed 104710(7MB) AllocSpace objects, 21(416KB) LOS objects, 33% free, 25MB/38MB, paused 1.230ms total 67.216ms |
| 125 | </pre> |
| 126 | |
| 127 | <dl> |
| 128 | <dt>GC Reason</dt> |
| 129 | <dd> |
| 130 | What triggered the GC and what kind of collection it is. Reasons that may appear |
| 131 | include: |
| 132 | <dl> |
| 133 | <dt><code>Concurrent</code></dt> |
| Rich Slogar | f6d03e5 | 2015-07-07 11:40:47 -0700 | [diff] [blame] | 134 | <dd>A concurrent GC which does not suspend app threads. This GC runs in a background thread |
| Mathieu Chartier | d92c6bde | 2015-03-23 15:58:11 -0700 | [diff] [blame] | 135 | and does not prevent allocations.</dd> |
| 136 | |
| 137 | <dt><code>Alloc</code></dt> |
| Rich Slogar | f6d03e5 | 2015-07-07 11:40:47 -0700 | [diff] [blame] | 138 | <dd>The GC was initiated because your app attempted to allocate memory when your heap |
| Mathieu Chartier | d92c6bde | 2015-03-23 15:58:11 -0700 | [diff] [blame] | 139 | was already full. In this case, the garbage collection occurred in the allocating thread.</dd> |
| 140 | |
| 141 | <dt><code>Explicit</code> |
| Rich Slogar | f6d03e5 | 2015-07-07 11:40:47 -0700 | [diff] [blame] | 142 | <dd>The garbage collection was explicitly requested by an app, for instance, by |
| Mathieu Chartier | d92c6bde | 2015-03-23 15:58:11 -0700 | [diff] [blame] | 143 | calling {@link java.lang.System#gc()} or {@link java.lang.Runtime#gc()}. As with Dalvik, in ART it is |
| 144 | recommended that you trust the GC and avoid requesting explicit GCs if possible. Explicit GCs are |
| 145 | discouraged since they block the allocating thread and unnecessarily was CPU cycles. Explicit GCs |
| 146 | could also cause jank if they cause other threads to get preempted.</dd> |
| 147 | |
| 148 | <dt><code>NativeAlloc</code></dt> |
| 149 | <dd>The collection was caused by native memory pressure from native allocations such as Bitmaps or |
| 150 | RenderScript allocation objects.</dd> |
| 151 | |
| 152 | <dt><code>CollectorTransition</code></dt> |
| 153 | <dd>The collection was caused by a heap transition; this is caused by switching the GC at run time. |
| 154 | Collector transitions consist of copying all the objects from a free-list backed |
| 155 | space to a bump pointer space (or visa versa). Currently collector transitions only occur when an |
| Rich Slogar | f6d03e5 | 2015-07-07 11:40:47 -0700 | [diff] [blame] | 156 | app changes process states from a pause perceptible state to a non pause perceptible state |
| Mathieu Chartier | d92c6bde | 2015-03-23 15:58:11 -0700 | [diff] [blame] | 157 | (or visa versa) on low RAM devices. |
| 158 | </dd> |
| 159 | |
| 160 | <dt><code>HomogeneousSpaceCompact</code></dt> |
| 161 | <dd>Homogeneous space compaction is free-list space to free-list space compaction which usually |
| Rich Slogar | f6d03e5 | 2015-07-07 11:40:47 -0700 | [diff] [blame] | 162 | occurs when an app is moved to a pause imperceptible process state. The main reasons for doing |
| Mathieu Chartier | d92c6bde | 2015-03-23 15:58:11 -0700 | [diff] [blame] | 163 | this are reducing RAM usage and defragmenting the heap. |
| 164 | </dd> |
| 165 | |
| 166 | <dt><code>DisableMovingGc</code></dt> |
| 167 | <dd>This is not a real GC reason, but a note that collection was blocked due to use of |
| 168 | GetPrimitiveArrayCritical. while concurrent heap compaction is occuring. In general, the use of |
| 169 | GetPrimitiveArrayCritical is strongly discouraged due to its restrictions on moving collectors. |
| 170 | </dd> |
| 171 | |
| 172 | <dt><code>HeapTrim</code></dt> |
| 173 | <dd>This is not a GC reason, but a note that collection was blocked until a heap trim finished. |
| 174 | </dd> |
| 175 | |
| 176 | </dl> |
| 177 | </dd> |
| 178 | |
| 179 | |
| 180 | <dl> |
| 181 | <dt>GC Name</dt> |
| 182 | <dd> |
| 183 | ART has various different GCs which can get run. |
| 184 | <dl> |
| 185 | <dt><code>Concurrent mark sweep (CMS)</code></dt> |
| 186 | <dd>A whole heap collector which frees collects all spaces other than the image space.</dd> |
| 187 | |
| 188 | <dt><code>Concurrent partial mark sweep</code></dt> |
| 189 | <dd>A mostly whole heap collector which collects all spaces other than the image and zygote spaces. |
| 190 | </dd> |
| 191 | |
| 192 | <dt><code>Concurrent sticky mark sweep</code></dt> |
| 193 | <dd>A generational collector which can only free objects allocated since the last GC. This garbage |
| 194 | collection is run more often than a full or partial mark sweep since it is faster and has lower pauses. |
| 195 | </dd> |
| 196 | |
| 197 | <dt><code>Marksweep + semispace</code></dt> |
| 198 | <dd>A non concurrent, copying GC used for heap transitions as well as homogeneous space |
| 199 | compaction (to defragement the heap).</dd> |
| 200 | |
| 201 | </dl> |
| 202 | </dd> |
| 203 | |
| 204 | <dt>Objects freed</dt> |
| 205 | <dd>The number of objects which were reclaimed from this GC from the non large |
| 206 | object space.</dd> |
| 207 | |
| 208 | <dt>Size freed</dt> |
| 209 | <dd>The number of bytes which were reclaimed from this GC from the non large object |
| 210 | space.</dd> |
| 211 | |
| 212 | <dt>Large objects freed</dt> |
| 213 | <dd>The number of object in the large object space which were reclaimed from this garbage |
| 214 | collection.</dd> |
| 215 | |
| 216 | <dt>Large object size freed</dt> |
| 217 | <dd>The number of bytes in the large object space which were reclaimed from this garbage |
| 218 | collection.</dd> |
| 219 | |
| 220 | <dt>Heap stats</dt> |
| 221 | <dd>Percentage free and (number of live objects)/(total heap size).</dd> |
| 222 | |
| 223 | <dt>Pause times</dt> |
| 224 | <dd>In general pause times are proportional to the number of object references which were modified |
| 225 | while the GC was running. Currently, the ART CMS GCs only has one pause, near the end of the GC. |
| 226 | The moving GCs have a long pause which lasts for the majority of the GC duration.</dd> |
| 227 | </dl> |
| 228 | |
| 229 | <p>If you are seeing a large amount of GCs in logcat, look for increases in the heap stats (the |
| 230 | {@code 25MB/38MB} value in the above example). If this value continues to increase and doesn't |
| 231 | ever seem to get smaller, you could have a memory leak. Alternatively, if you are seeing GC which |
| 232 | are for the reason "Alloc", then you are already operating near your heap capacity and can expect |
| Rich Slogar | f6d03e5 | 2015-07-07 11:40:47 -0700 | [diff] [blame] | 233 | OOM exceptions in the near future. </p> |
| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 234 | |
| 235 | <h2 id="ViewHeap">Viewing Heap Updates</h2> |
| 236 | |
| Rich Slogar | f6d03e5 | 2015-07-07 11:40:47 -0700 | [diff] [blame] | 237 | <p>To get a little information about what kind of memory your app is using and when, you |
| 238 | can view real-time updates to your app's heap in Android Studio's |
| 239 | <a href="{@docRoot}tools/studio/index.html#heap-dump">HPROF viewer</a> or in the Device Monitor:</p> |
| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 240 | |
| Rich Slogar | f6d03e5 | 2015-07-07 11:40:47 -0700 | [diff] [blame] | 241 | <h3>Memory Monitor in Android Studio</h3> |
| 242 | <p>Use Android Studio to view your app's memory use: </p> |
| 243 | <ul> |
| 244 | <li>Start your app on a connected device or emulator.</li> |
| 245 | <li>Open the Android run-time window, and view the free and allocated memory in the Memory |
| 246 | Monitor. </li> |
| 247 | <li>Click the Dump Java Heap icon |
| 248 | (<img src="{@docRoot}images/tools/studio-dump-heap-icon.png" style="vertical-align:bottom;margin:0;height:21px"/>) |
| 249 | in the Memory Monitor toolbar. |
| 250 | <p>Android Studio creates the heap snapshot file with the filename |
| 251 | <code>Snapshot-yyyy.mm.dd-hh.mm.ss.hprof</code> in the <em>Captures</em> tab. </p> |
| 252 | </li> |
| 253 | <li>Double-click the heap snapshot file to open the HPROF viewer. |
| 254 | <p class="note"><strong>Note:</strong> To convert a heap dump to standard HPROF format in |
| 255 | Android Studio, right-click a heap snapshot in the <em>Captures</em> view and select |
| 256 | <strong>Export to standard .hprof</strong>.</p> </li> |
| 257 | <li>Interact with your app and click the |
| 258 | (<img src="{@docRoot}images/tools/studio-garbage-collect.png" style="vertical-align:bottom;margin:0;height:17px"/>) |
| 259 | icon to cause heap allocation. |
| 260 | </li> |
| 261 | <li>Identify which actions in your app are likely causing too much allocation and determine where |
| 262 | in your app you should try to reduce allocations and release resources. |
| 263 | </ul> |
| 264 | |
| 265 | <h3>Device Monitor </h3> |
| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 266 | <ol> |
| 267 | <li>Open the Device Monitor. |
| 268 | <p>From your <code><sdk>/tools/</code> directory, launch the <code>monitor</code> tool.</p> |
| 269 | </li> |
| 270 | <li>In the Debug Monitor window, select your app's process from the list on the left.</li> |
| 271 | <li>Click <strong>Update Heap</strong> above the process list.</li> |
| 272 | <li>In the right-side panel, select the <strong>Heap</strong> tab.</li> |
| 273 | </ol> |
| 274 | |
| 275 | <p>The Heap view shows some basic stats about your heap memory usage, updated after every |
| Mathieu Chartier | d92c6bde | 2015-03-23 15:58:11 -0700 | [diff] [blame] | 276 | GC. To see the first update, click the <strong>Cause GC</strong> button.</p> |
| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 277 | |
| 278 | <img src="{@docRoot}images/tools/monitor-vmheap@2x.png" width="760" alt="" /> |
| 279 | <p class="img-caption"><strong>Figure 1.</strong> The Device Monitor tool, |
| 280 | showing the <strong>[1] Update Heap</strong> and <strong>[2] Cause GC</strong> buttons. |
| 281 | The Heap tab on the right shows the heap results.</p> |
| 282 | |
| Rich Slogar | f6d03e5 | 2015-07-07 11:40:47 -0700 | [diff] [blame] | 283 | |
| 284 | <p>Continue interacting with your app to watch your heap allocation update with each garbage |
| 285 | collection. This can help you identify which actions in your app are likely causing too much |
| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 286 | allocation and where you should try to reduce allocations and release |
| 287 | resources.</p> |
| 288 | |
| 289 | |
| 290 | |
| 291 | <h2 id="TrackAllocations">Tracking Allocations</h2> |
| 292 | |
| 293 | <p>As you start narrowing down memory issues, you should also use the Allocation Tracker to |
| 294 | get a better understanding of where your memory-hogging objects are allocated. The Allocation |
| 295 | Tracker can be useful not only for looking at specific uses of memory, but also to analyze critical |
| Rich Slogar | f6d03e5 | 2015-07-07 11:40:47 -0700 | [diff] [blame] | 296 | code paths in an app such as scrolling.</p> |
| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 297 | |
| Rich Slogar | f6d03e5 | 2015-07-07 11:40:47 -0700 | [diff] [blame] | 298 | <p>For example, tracking allocations when flinging a list in your app allows you to see all the |
| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 299 | allocations that need to be done for that behavior, what thread they are on, and where they came |
| 300 | from. This is extremely valuable for tightening up these paths to reduce the work they need and |
| 301 | improve the overall smoothness of the UI.</p> |
| 302 | |
| Rich Slogar | e5fe246 | 2015-07-07 12:17:02 -0700 | [diff] [blame^] | 303 | <p>To use the Allocation Tracker, open the Memory Monitor in Android Studio and click the |
| 304 | <a href="{@docRoot}tools/studio/index.html#alloc-tracker" style="vertical-align:bottom;margin:0;height:21px"> |
| 305 | Allocation Tracker</a> icon. You can also track allocations in the Android Device Monitor:</p> |
| 306 | |
| 307 | |
| 308 | <h3>Android Studio </h3> |
| 309 | <p>To use the <a href="{@docRoot}tools/studio/index.html#alloc-tracker">Allocation Tracker</a> in |
| 310 | Android Studio: </p> |
| 311 | |
| 312 | <ol> |
| 313 | <li>Start your app on a connected device or emulator</li> |
| 314 | <li>Open the Android run-tme window, and view the free and allocated memory in the Memory |
| 315 | Monitor. </li> |
| 316 | <li>Click the Allocation Tracker icon |
| 317 | (<img src="{@docRoot}images/tools/studio-allocation-tracker-icon.png" style="vertical-align:bottom;margin:0;height:21px"/>) in the Memory Monitor tool bar to start and stop memory |
| 318 | allocations. |
| 319 | <p>Android Studio creates the allocation file with the filename |
| 320 | <code>Allocations-yyyy.mm.dd-hh.mm.ss.alloc</code> in the <em>Captures</em> tab. </p> |
| 321 | </li> |
| 322 | <li>Double-click the allocation file to open the Allocation viewer. </li> |
| 323 | <li>Identify which actions in your app are likely causing too much allocation and determine where |
| 324 | in your app you should try to reduce allocations and release resources. |
| 325 | </ol> |
| 326 | |
| 327 | |
| 328 | |
| 329 | <h3>Device Monitor</h3> |
| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 330 | <ol> |
| 331 | <li>Open the Device Monitor. |
| 332 | <p>From your <code><sdk>/tools/</code> directory, launch the <code>monitor</code> tool.</p> |
| 333 | </li> |
| 334 | <li>In the DDMS window, select your app's process in the left-side panel.</li> |
| 335 | <li>In the right-side panel, select the <strong>Allocation Tracker</strong> tab.</li> |
| 336 | <li>Click <strong>Start Tracking</strong>.</li> |
| Rich Slogar | f6d03e5 | 2015-07-07 11:40:47 -0700 | [diff] [blame] | 337 | <li>Interact with your app to execute the code paths you want to analyze.</li> |
| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 338 | <li>Click <strong>Get Allocations</strong> every time you want to update the |
| 339 | list of allocations.</li> |
| 340 | </ol> |
| 341 | |
| 342 | <p>The list shows all recent allocations, |
| 343 | currently limited by a 512-entry ring buffer. Click on a line to see the stack trace that led to |
| 344 | the allocation. The trace shows you not only what type of object was allocated, but also in which |
| 345 | thread, in which class, in which file and at which line.</p> |
| 346 | |
| 347 | <img src="{@docRoot}images/tools/monitor-tracker@2x.png" width="760" alt="" /> |
| 348 | <p class="img-caption"><strong>Figure 2.</strong> The Device Monitor tool, |
| Rich Slogar | f6d03e5 | 2015-07-07 11:40:47 -0700 | [diff] [blame] | 349 | showing recent app allocations and stack traces in the Allocation Tracker.</p> |
| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 350 | |
| 351 | |
| 352 | <p class="note"><strong>Note:</strong> You will always see some allocations from {@code |
| 353 | DdmVmInternal} and else where that come from the allocation tracker itself.</p> |
| 354 | |
| 355 | <p>Although it's not necessary (nor possible) to remove all allocations for your performance |
| 356 | critical code paths, the allocation tracker can help you identify important issues in your code. |
| 357 | For instance, some apps might create a new {@link android.graphics.Paint} object on every draw. |
| 358 | Moving that object into a global member is a simple fix that helps improve performance.</p> |
| 359 | |
| 360 | |
| 361 | |
| 362 | |
| 363 | |
| 364 | |
| 365 | <h2 id="ViewingAllocations">Viewing Overall Memory Allocations</h2> |
| 366 | |
| Scott Main | 4c6b1af | 2013-11-11 17:33:32 -0800 | [diff] [blame] | 367 | <p>For further analysis, you may want to observe how your app's memory is |
| 368 | divided between different types of RAM allocation with the |
| 369 | following <a href="{@docRoot}tools/help/adb.html">adb</a> command:</p> |
| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 370 | |
| Scott Main | 4c6b1af | 2013-11-11 17:33:32 -0800 | [diff] [blame] | 371 | <pre class="no-pretty-print"> |
| Mathieu Chartier | d92c6bde | 2015-03-23 15:58:11 -0700 | [diff] [blame] | 372 | adb shell dumpsys meminfo <package_name|pid> [-d] |
| Scott Main | 4c6b1af | 2013-11-11 17:33:32 -0800 | [diff] [blame] | 373 | </pre> |
| 374 | |
| Mathieu Chartier | d92c6bde | 2015-03-23 15:58:11 -0700 | [diff] [blame] | 375 | <p>The -d flag prints more info related to Dalvik and ART memory usage.</p> |
| 376 | |
| Scott Main | 4c6b1af | 2013-11-11 17:33:32 -0800 | [diff] [blame] | 377 | <p>The output lists all of your app's current allocations, measured in kilobytes.</p> |
| 378 | |
| 379 | <p>When inspecting this information, you should be familiar with the |
| 380 | following types of allocation:</p> |
| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 381 | |
| 382 | <dl> |
| 383 | <dt>Private (Clean and Dirty) RAM</dt> |
| 384 | <dd>This is memory that is being used by only your process. This is the bulk of the RAM that the system |
| 385 | can reclaim when your app’s process is destroyed. Generally, the most important portion of this is |
| 386 | “private dirty” RAM, which is the most expensive because it is used by only your process and its |
| 387 | contents exist only in RAM so can’t be paged to storage (because Android does not use swap). All |
| 388 | Dalvik and native heap allocations you make will be private dirty RAM; Dalvik and native |
| 389 | allocations you share with the Zygote process are shared dirty RAM.</dd> |
| 390 | |
| 391 | <dt>Proportional Set Size (PSS)</dt> |
| 392 | <dd>This is a measurement of your app’s RAM use that takes into account sharing pages across processes. |
| 393 | Any RAM pages that are unique to your process directly contribute to its PSS value, while pages |
| 394 | that are shared with other processes contribute to the PSS value only in proportion to the amount |
| 395 | of sharing. For example, a page that is shared between two processes will contribute half of its |
| 396 | size to the PSS of each process.</dd> |
| 397 | </dl> |
| 398 | |
| 399 | |
| 400 | <p>A nice characteristic of the PSS measurement is that you can add up the PSS across all processes to |
| 401 | determine the actual memory being used by all processes. This means PSS is a good measure for the |
| 402 | actual RAM weight of a process and for comparison against the RAM use of other processes and the |
| 403 | total available RAM.</p> |
| 404 | |
| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 405 | |
| Mathieu Chartier | d92c6bde | 2015-03-23 15:58:11 -0700 | [diff] [blame] | 406 | <p>For example, below is the the output for Map’s process on a Nexus 5 device. There is a lot of |
| Scott Main | 4c6b1af | 2013-11-11 17:33:32 -0800 | [diff] [blame] | 407 | information here, but key points for discussion are listed below.</p> |
| Mathieu Chartier | d92c6bde | 2015-03-23 15:58:11 -0700 | [diff] [blame] | 408 | <code>adb shell dumpsys meminfo com.google.android.apps.maps -d</code> |
| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 409 | |
| 410 | <p class="note"><strong>Note:</strong> The information you see may vary slightly from what is shown |
| 411 | here, as some details of the output differ across platform versions.</p> |
| 412 | |
| 413 | <pre class="no-pretty-print"> |
| Mathieu Chartier | d92c6bde | 2015-03-23 15:58:11 -0700 | [diff] [blame] | 414 | ** MEMINFO in pid 18227 [com.google.android.apps.maps] ** |
| 415 | Pss Private Private Swapped Heap Heap Heap |
| 416 | Total Dirty Clean Dirty Size Alloc Free |
| 417 | ------ ------ ------ ------ ------ ------ ------ |
| 418 | Native Heap 10468 10408 0 0 20480 14462 6017 |
| 419 | Dalvik Heap 34340 33816 0 0 62436 53883 8553 |
| 420 | Dalvik Other 972 972 0 0 |
| 421 | Stack 1144 1144 0 0 |
| 422 | Gfx dev 35300 35300 0 0 |
| 423 | Other dev 5 0 4 0 |
| 424 | .so mmap 1943 504 188 0 |
| 425 | .apk mmap 598 0 136 0 |
| 426 | .ttf mmap 134 0 68 0 |
| 427 | .dex mmap 3908 0 3904 0 |
| 428 | .oat mmap 1344 0 56 0 |
| 429 | .art mmap 2037 1784 28 0 |
| 430 | Other mmap 30 4 0 0 |
| 431 | EGL mtrack 73072 73072 0 0 |
| 432 | GL mtrack 51044 51044 0 0 |
| 433 | Unknown 185 184 0 0 |
| 434 | TOTAL 216524 208232 4384 0 82916 68345 14570 |
| 435 | |
| 436 | Dalvik Details |
| 437 | .Heap 6568 6568 0 0 |
| 438 | .LOS 24771 24404 0 0 |
| 439 | .GC 500 500 0 0 |
| 440 | .JITCache 428 428 0 0 |
| 441 | .Zygote 1093 936 0 0 |
| 442 | .NonMoving 1908 1908 0 0 |
| 443 | .IndirectRef 44 44 0 0 |
| 444 | |
| 445 | Objects |
| 446 | Views: 90 ViewRootImpl: 1 |
| 447 | AppContexts: 4 Activities: 1 |
| 448 | Assets: 2 AssetManagers: 2 |
| 449 | Local Binders: 21 Proxy Binders: 28 |
| 450 | Parcel memory: 18 Parcel count: 74 |
| 451 | Death Recipients: 2 OpenSSL Sockets: 2 |
| 452 | </pre> |
| 453 | |
| 454 | <p>Here is an older dumpsys on Dalvik of the gmail app:</p> |
| 455 | |
| 456 | <pre class="no-pretty-print"> |
| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 457 | ** MEMINFO in pid 9953 [com.google.android.gm] ** |
| 458 | Pss Pss Shared Private Shared Private Heap Heap Heap |
| 459 | Total Clean Dirty Dirty Clean Clean Size Alloc Free |
| 460 | ------ ------ ------ ------ ------ ------ ------ ------ ------ |
| 461 | Native Heap 0 0 0 0 0 0 7800 7637(6) 126 |
| 462 | Dalvik Heap 5110(3) 0 4136 4988(3) 0 0 9168 8958(6) 210 |
| 463 | Dalvik Other 2850 0 2684 2772 0 0 |
| 464 | Stack 36 0 8 36 0 0 |
| 465 | Cursor 136 0 0 136 0 0 |
| 466 | Ashmem 12 0 28 0 0 0 |
| 467 | Other dev 380 0 24 376 0 4 |
| 468 | .so mmap 5443(5) 1996 2584 2664(5) 5788 1996(5) |
| 469 | .apk mmap 235 32 0 0 1252 32 |
| 470 | .ttf mmap 36 12 0 0 88 12 |
| 471 | .dex mmap 3019(5) 2148 0 0 8936 2148(5) |
| 472 | Other mmap 107 0 8 8 324 68 |
| 473 | Unknown 6994(4) 0 252 6992(4) 0 0 |
| 474 | TOTAL 24358(1) 4188 9724 17972(2)16388 4260(2)16968 16595 336 |
| Ricardo Cervera | 2102ac1 | 2014-10-21 10:12:08 -0700 | [diff] [blame] | 475 | |
| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 476 | Objects |
| 477 | Views: 426 ViewRootImpl: 3(8) |
| 478 | AppContexts: 6(7) Activities: 2(7) |
| 479 | Assets: 2 AssetManagers: 2 |
| 480 | Local Binders: 64 Proxy Binders: 34 |
| 481 | Death Recipients: 0 |
| 482 | OpenSSL Sockets: 1 |
| Ricardo Cervera | 2102ac1 | 2014-10-21 10:12:08 -0700 | [diff] [blame] | 483 | |
| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 484 | SQL |
| 485 | MEMORY_USED: 1739 |
| 486 | PAGECACHE_OVERFLOW: 1164 MALLOC_SIZE: 62 |
| 487 | </pre> |
| 488 | |
| 489 | <p>Generally, you should be concerned with only the <code>Pss Total</code> and <code>Private Dirty</code> |
| 490 | columns. In some cases, the <code>Private Clean</code> and <code>Heap Alloc</code> columns also offer |
| 491 | interesting data. Here is some more information about the different memory allocations (the rows) |
| 492 | you should observe: |
| 493 | |
| 494 | <dl> |
| 495 | <dt><code>Dalvik Heap</code></dt> |
| 496 | <dd>The RAM used by Dalvik allocations in your app. The <code>Pss Total</code> includes all Zygote |
| 497 | allocations (weighted by their sharing across processes, as described in the PSS definition above). |
| 498 | The <code>Private Dirty</code> number is the actual RAM committed to only your app’s heap, composed of |
| 499 | your own allocations and any Zygote allocation pages that have been modified since forking your |
| 500 | app’s process from Zygote. |
| 501 | |
| 502 | <p class="note"><strong>Note:</strong> On newer platform versions that have the <code>Dalvik |
| 503 | Other</code> section, the <code>Pss Total</code> and <code>Private Dirty</code> numbers for Dalvik Heap do |
| Mathieu Chartier | d92c6bde | 2015-03-23 15:58:11 -0700 | [diff] [blame] | 504 | not include Dalvik overhead such as the just-in-time compilation (JIT) and GC |
| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 505 | bookkeeping, whereas older versions list it all combined under <code>Dalvik</code>.</p> |
| 506 | |
| 507 | <p>The <code>Heap Alloc</code> is the amount of memory that the Dalvik and native heap allocators keep |
| 508 | track of for your app. This value is larger than <code>Pss Total</code> and <code>Private Dirty</code> |
| 509 | because your process was forked from Zygote and it includes allocations that your process shares |
| 510 | with all the others.</p> |
| 511 | </dd> |
| 512 | |
| 513 | <dt><code>.so mmap</code> and <code>.dex mmap</code></dt> |
| Rich Slogar | f6d03e5 | 2015-07-07 11:40:47 -0700 | [diff] [blame] | 514 | <dd>The RAM being used for mapped <code>.so</code> (native) and <code>.dex</code> (Dalvik or ART) |
| Mathieu Chartier | d92c6bde | 2015-03-23 15:58:11 -0700 | [diff] [blame] | 515 | code. The <code>Pss Total</code> number includes platform code shared across apps; the |
| 516 | <code>Private Clean</code> is your app’s own code. Generally, the actual mapped size will be much |
| 517 | larger—the RAM here is only what currently needs to be in RAM for code that has been executed by |
| 518 | the app. However, the .so mmap has a large private dirty, which is due to fix-ups to the native |
| 519 | code when it was loaded into its final address. |
| 520 | </dd> |
| 521 | |
| 522 | <dt><code>.oat mmap</code></dt> |
| 523 | <dd>This is the amount of RAM used by the code image which is based off of the preloaded classes |
| 524 | which are commonly used by multiple apps. This image is shared across all apps and is unaffected |
| 525 | by particular apps. |
| 526 | </dd> |
| 527 | |
| 528 | <dt><code>.art mmap</code></dt> |
| 529 | <dd>This is the amount of RAM used by the heap image which is based off of the preloaded classes |
| 530 | which are commonly used by multiple apps. This image is shared across all apps and is unaffected |
| 531 | by particular apps. Even though the ART image contains {@link java.lang.Object} instances, it does not |
| 532 | count towards your heap size. |
| 533 | </dd> |
| 534 | |
| 535 | <dt><code>.Heap</code> (only with -d flag)</dt> |
| 536 | <dd>This is the amount of heap memory for your app. This excludes objects in the image and large |
| 537 | object spaces, but includes the zygote space and non-moving space. |
| 538 | </dd> |
| 539 | |
| 540 | <dt><code>.LOS</code> (only with -d flag)</dt> |
| 541 | <dd>This is the amount of RAM used by the ART large object space. This includes zygote large |
| 542 | objects. Large objects are all primitive array allocations larger than 12KB. |
| 543 | </dd> |
| 544 | |
| 545 | <dt><code>.GC</code> (only with -d flag)</dt> |
| 546 | <dd>This is the amount of internal GC accounting overhead for your app. There is not really any way |
| 547 | to reduce this overhead. |
| 548 | </dd> |
| 549 | |
| 550 | <dt><code>.JITCache</code> (only with -d flag)</dt> |
| 551 | <dd>This is the amount of memory used by the JIT data and code caches. Typically, this is zero |
| 552 | since all of the apps will be compiled at installed time. |
| 553 | </dd> |
| 554 | |
| 555 | <dt><code>.Zygote</code> (only with -d flag)</dt> |
| 556 | <dd>This is the amount of memory used by the zygote space. The zygote space is created during |
| 557 | device startup and is never allocated into. |
| 558 | </dd> |
| 559 | |
| 560 | <dt><code>.NonMoving</code> (only with -d flag)</dt> |
| 561 | <dd>This is the amount of RAM used by the ART non-moving space. The non-moving space contains |
| 562 | special non-movable objects such as fields and methods. You can reduce this section by using fewer |
| 563 | fields and methods in your app. |
| 564 | </dd> |
| 565 | |
| 566 | <dt><code>.IndirectRef</code> (only with -d flag)</dt> |
| 567 | <dd>This is the amount of RAM used by the ART indirect reference tables. Usually this amount is |
| 568 | small, but if it is too high, it may be possible to reduce it by reducing the number of local and |
| 569 | global JNI references used. |
| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 570 | </dd> |
| 571 | |
| 572 | <dt><code>Unknown</code></dt> |
| 573 | <dd>Any RAM pages that the system could not classify into one of the other more specific items. |
| 574 | Currently, this contains mostly native allocations, which cannot be identified by the tool when |
| 575 | collecting this data due to Address Space Layout Randomization (ASLR). As with the Dalvik heap, the |
| 576 | <code>Pss Total</code> for Unknown takes into account sharing with Zygote, and <code>Private Dirty</code> |
| 577 | is unknown RAM dedicated to only your app. |
| 578 | </dd> |
| 579 | |
| 580 | <dt><code>TOTAL</code></dt> |
| 581 | <dd>The total Proportional Set Size (PSS) RAM used by your process. This is the sum of all PSS fields |
| 582 | above it. It indicates the overall memory weight of your process, which can be directly compared |
| 583 | with other processes and the total available RAM. |
| 584 | |
| 585 | <p>The <code>Private Dirty</code> and <code>Private Clean</code> are the total allocations within your |
| 586 | process, which are not shared with other processes. Together (especially <code>Private Dirty</code>), |
| 587 | this is the amount of RAM that will be released back to the system when your process is destroyed. |
| 588 | Dirty RAM is pages that have been modified and so must stay committed to RAM (because there is no |
| 589 | swap); clean RAM is pages that have been mapped from a persistent file (such as code being |
| 590 | executed) and so can be paged out if not used for a while.</p> |
| 591 | |
| 592 | </dd> |
| 593 | |
| 594 | <dt><code>ViewRootImpl</code></dt> |
| 595 | <dd>The number of root views that are active in your process. Each root view is associated with a |
| 596 | window, so this can help you identify memory leaks involving dialogs or other windows. |
| 597 | </dd> |
| 598 | |
| 599 | <dt><code>AppContexts</code> and <code>Activities</code></dt> |
| Rich Slogar | f6d03e5 | 2015-07-07 11:40:47 -0700 | [diff] [blame] | 600 | <dd>The number of app {@link android.content.Context} and {@link android.app.Activity} objects that |
| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 601 | currently live in your process. This can be useful to quickly identify leaked {@link |
| 602 | android.app.Activity} objects that can’t be garbage collected due to static references on them, |
| 603 | which is common. These objects often have a lot of other allocations associated with them and so |
| 604 | are a good way to track large memory leaks.</dd> |
| 605 | |
| 606 | <p class="note"><strong>Note:</strong> A {@link android.view.View} or {@link |
| 607 | android.graphics.drawable.Drawable} object also holds a reference to the {@link |
| 608 | android.app.Activity} that it's from, so holding a {@link android.view.View} or {@link |
| Rich Slogar | f6d03e5 | 2015-07-07 11:40:47 -0700 | [diff] [blame] | 609 | android.graphics.drawable.Drawable} object can also lead to your app leaking an {@link |
| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 610 | android.app.Activity}.</p> |
| 611 | |
| 612 | </dd> |
| 613 | </dl> |
| 614 | |
| 615 | |
| 616 | |
| 617 | |
| 618 | |
| 619 | |
| 620 | |
| 621 | |
| 622 | |
| 623 | <h2 id="HeapDump">Capturing a Heap Dump</h2> |
| 624 | |
| 625 | <p>A heap dump is a snapshot of all the objects in your app's heap, stored in a binary format called |
| 626 | HPROF. Your app's heap dump provides information about the overall state of your app's heap so you |
| 627 | can track down problems you might have identified while viewing heap updates.</p> |
| 628 | |
| Rich Slogar | f6d03e5 | 2015-07-07 11:40:47 -0700 | [diff] [blame] | 629 | |
| 630 | <p>To retrieve your heap dump from within Android Studio, use the |
| 631 | <a href="{@docRoot}tools/studio/index.html#me-cpu">Memory Monitor</a> and |
| 632 | <a href="{@docRoot}tools/studio/index.html#heap-dump">HPROF viewer</a>. |
| 633 | |
| 634 | <p>You can also still perform these procedures in the Android monitor:</p> |
| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 635 | <ol> |
| 636 | <li>Open the Device Monitor. |
| 637 | <p>From your <code><sdk>/tools/</code> directory, launch the <code>monitor</code> tool.</p> |
| 638 | </li> |
| 639 | <li>In the DDMS window, select your app's process in the left-side panel.</li> |
| 640 | <li>Click <strong>Dump HPROF file</strong>, shown in figure 3.</li> |
| 641 | <li>In the window that appears, name your HPROF file, select the save location, |
| 642 | then click <strong>Save</strong>.</li> |
| 643 | </ol> |
| 644 | |
| 645 | <img src="{@docRoot}images/tools/monitor-hprof@2x.png" width="760" alt="" /> |
| 646 | <p class="img-caption"><strong>Figure 3.</strong> The Device Monitor tool, |
| 647 | showing the <strong>[1] Dump HPROF file</strong> button.</p> |
| 648 | |
| 649 | <p>If you need to be more precise about when the dump is created, you can also create a heap dump |
| Rich Slogar | f6d03e5 | 2015-07-07 11:40:47 -0700 | [diff] [blame] | 650 | at the critical point in your app code by calling {@link android.os.Debug#dumpHprofData |
| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 651 | dumpHprofData()}.</p> |
| 652 | |
| 653 | <p>The heap dump is provided in a format that's similar to, but not identical to one from the Java |
| 654 | HPROF tool. The major difference in an Android heap dump is due to the fact that there are a large |
| 655 | number of allocations in the Zygote process. But because the Zygote allocations are shared across |
| Rich Slogar | f6d03e5 | 2015-07-07 11:40:47 -0700 | [diff] [blame] | 656 | all app processes, they don’t matter very much to your own heap analysis.</p> |
| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 657 | |
| 658 | <p>To analyze your heap dump, you can use a standard tool like jhat or the <a href= |
| 659 | "http://www.eclipse.org/mat/downloads.php">Eclipse Memory Analyzer Tool</a> (MAT). However, first |
| 660 | you'll need to convert the HPROF file from Android's format to the J2SE HPROF format. You can do |
| Ricardo Cervera | 2102ac1 | 2014-10-21 10:12:08 -0700 | [diff] [blame] | 661 | this using the <code>hprof-conv</code> tool provided in the <code><sdk>/platform-tools/</code> |
| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 662 | directory. Simply run the <code>hprof-conv</code> command with two arguments: the original HPROF |
| 663 | file and the location to write the converted HPROF file. For example:</p> |
| 664 | |
| 665 | <pre class="no-pretty-print"> |
| 666 | hprof-conv heap-original.hprof heap-converted.hprof |
| 667 | </pre> |
| 668 | |
| 669 | <p class="note"><strong>Note:</strong> If you're using the version of DDMS that's integrated into |
| Rich Slogar | e5fe246 | 2015-07-07 12:17:02 -0700 | [diff] [blame^] | 670 | Eclipse, you do not need to perform the HPROF conversation—it performs the conversion by |
| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 671 | default.</p> |
| 672 | |
| 673 | <p>You can now load the converted file in MAT or another heap analysis tool that understands |
| 674 | the J2SE HPROF format.</p> |
| 675 | |
| 676 | <p>When analyzing your heap, you should look for memory leaks caused by:</p> |
| 677 | <ul> |
| 678 | <li>Long-lived references to an Activity, Context, View, Drawable, and other objects that may hold a |
| 679 | reference to the container Activity or Context.</li> |
| 680 | <li>Non-static inner classes (such as a Runnable, which can hold the Activity instance).</li> |
| 681 | <li>Caches that hold objects longer than necessary.</li> |
| 682 | </ul> |
| 683 | |
| 684 | |
| 685 | <h3 id="EclipseMat">Using the Eclipse Memory Analyzer Tool</h3> |
| 686 | |
| 687 | <p>The <a href= |
| 688 | "http://www.eclipse.org/mat/downloads.php">Eclipse Memory Analyzer Tool</a> (MAT) is just one |
| 689 | tool that you can use to analyze your heap dump. It's also quite powerful so most of its |
| 690 | capabilities are beyond the scope of this document, but here are a few tips to get you started. |
| 691 | |
| 692 | <p>Once you open your converted HPROF file in MAT, you'll see a pie chart in the Overview, |
| 693 | showing what your largest objects are. Below this chart, are links to couple of useful features:</p> |
| 694 | |
| 695 | <ul> |
| 696 | <li>The <strong>Histogram view</strong> shows a list of all classes and how many instances |
| 697 | there are of each. |
| 698 | <p>You might want to use this view to find extra instances of classes for which you know there |
| 699 | should be only a certain number. For example, a common source of leaks is additional instance of |
| 700 | your {@link android.app.Activity} class, for which you should usually have only one instance |
| 701 | at a time. To find a specific class instance, type the class name into the <em><Regex></em> |
| 702 | field at the top of the list. |
| 703 | <p>When you find a class with too many instances, right-click it and select |
| 704 | <strong>List objects</strong> > <strong>with incoming references</strong>. In the list that |
| 705 | appears, you can determine where an instance is retained by right-clicking it and selecting |
| 706 | <strong>Path To GC Roots</strong> > <strong>exclude weak references</strong>.</p> |
| 707 | </li> |
| 708 | |
| 709 | <li>The <strong>Dominator tree</strong> shows a list of objects organized by the amount |
| 710 | of retained heap. |
| 711 | <p>What you should look for is anything that's retaining a portion of heap that's roughly |
| 712 | equivalent to the memory size you observed leaking from the <a href="#LogMessages">GC logs</a>, |
| 713 | <a href="#ViewHeap">heap updates</a>, or <a href="#TrackAllocations">allocation |
| 714 | tracker</a>. |
| 715 | <p>When you see something suspicious, right-click on the item and select |
| 716 | <strong>Path To GC Roots</strong> > <strong>exclude weak references</strong>. This opens a |
| 717 | new tab that traces the references to that object which is causing the alleged leak.</p> |
| 718 | |
| 719 | <p class="note"><strong>Note:</strong> Most apps will show an instance of |
| 720 | {@link android.content.res.Resources} near the top with a good chunk of heap, but this is |
| Rich Slogar | f6d03e5 | 2015-07-07 11:40:47 -0700 | [diff] [blame] | 721 | usually expected when your app uses lots of resources from your {@code res/} directory.</p> |
| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 722 | </li> |
| 723 | </ul> |
| 724 | |
| 725 | |
| 726 | <img src="{@docRoot}images/tools/mat-histogram@2x.png" width="760" alt="" /> |
| 727 | <p class="img-caption"><strong>Figure 4.</strong> The Eclipse Memory Analyzer Tool (MAT), |
| 728 | showing the Histogram view and a search for "MainActivity".</p> |
| 729 | |
| 730 | <p>For more information about MAT, watch the Google I/O 2011 presentation, |
| 731 | <a href="http://www.youtube.com/watch?v=_CruQY55HOk">Memory management for Android apps</a>, |
| 732 | which includes a walkthrough using MAT beginning at about <a href= |
| 733 | "http://www.youtube.com/watch?v=_CruQY55HOk&feature=player_detailpage#t=1270">21:10</a>. |
| 734 | Also refer to the <a href="http://wiki.eclipse.org/index.php/MemoryAnalyzer">Eclipse Memory |
| 735 | Analyzer documentation</a>.</p> |
| 736 | |
| 737 | <h4 id="MatCompare">Comparing heap dumps</h4> |
| 738 | |
| 739 | <p>You may find it useful to compare your app's heap state at two different points in time in order |
| 740 | to inspect the changes in memory allocation. To compare two heap dumps using MAT:</p> |
| 741 | |
| 742 | <ol> |
| 743 | <li>Create two HPROF files as described above, in <a href="#HeapDump">Capturing a Heap Dump</a>. |
| 744 | <li>Open the first HPROF file in MAT (<strong>File</strong> > <strong>Open Heap Dump</strong>). |
| 745 | <li>In the Navigation History view (if not visible, select <strong>Window</strong> > |
| 746 | <strong>Navigation History</strong>), right-click on <strong>Histogram</strong> and select |
| 747 | <strong>Add to Compare Basket</strong>. |
| 748 | <li>Open the second HPROF file and repeat steps 2 and 3. |
| 749 | <li>Switch to the <em>Compare Basket</em> view and click <strong>Compare the Results</strong> |
| 750 | (the red "!" icon in the top-right corner of the view). |
| 751 | </ol> |
| 752 | |
| 753 | |
| 754 | |
| 755 | |
| 756 | |
| 757 | |
| 758 | <h2 id="TriggerLeaks">Triggering Memory Leaks</h2> |
| 759 | |
| Rich Slogar | f6d03e5 | 2015-07-07 11:40:47 -0700 | [diff] [blame] | 760 | <p>While using the tools described above, you should aggressively stress your app code and try |
| 761 | forcing memory leaks. One way to provoke memory leaks in your app is to let it |
| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 762 | run for a while before inspecting the heap. Leaks will trickle up to the top of the allocations in |
| Rich Slogar | f6d03e5 | 2015-07-07 11:40:47 -0700 | [diff] [blame] | 763 | the heap. However, the smaller the leak, the longer you need to run the app in order to see it.</p> |
| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 764 | |
| 765 | <p>You can also trigger a memory leak in one of the following ways:</p> |
| 766 | <ol> |
| 767 | <li>Rotate the device from portrait to landscape and back again multiple times while in different |
| Rich Slogar | f6d03e5 | 2015-07-07 11:40:47 -0700 | [diff] [blame] | 768 | activity states. Rotating the device can often cause an app to leak an {@link android.app.Activity}, |
| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 769 | {@link android.content.Context}, or {@link android.view.View} object because the system |
| Rich Slogar | f6d03e5 | 2015-07-07 11:40:47 -0700 | [diff] [blame] | 770 | recreates the {@link android.app.Activity} and if your app holds a reference |
| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 771 | to one of those objects somewhere else, the system can't garbage collect it.</li> |
| Rich Slogar | f6d03e5 | 2015-07-07 11:40:47 -0700 | [diff] [blame] | 772 | <li>Switch between your app and another app while in different activity states (navigate to |
| Scott Main | a3f0e01 | 2013-09-19 17:45:40 -0700 | [diff] [blame] | 773 | the Home screen, then return to your app).</li> |
| 774 | </ol> |
| 775 | |
| 776 | <p class="note"><strong>Tip:</strong> You can also perform the above steps by using the "monkey" |
| 777 | test framework. For more information on running the monkey test framework, read the <a href= |
| 778 | "{@docRoot}tools/help/monkeyrunner_concepts.html">monkeyrunner</a> |
| Joe Fernandez | 33baa5a | 2013-11-14 11:41:19 -0800 | [diff] [blame] | 779 | documentation.</p> |