1# Memory: Java heap dumps 2 3NOTE: Capturing Java heap dumps requires Android 11 or higher 4 5See the [Memory Guide](/docs/case-studies/memory.md#java-hprof) for getting 6started with Java heap dumps. 7 8Conversely from [Native heap profiles](native-heap-profiler.md), Java heap dumps 9report full retention graphs of managed objects but not call-stacks. The 10information recorded in a Java heap dump is of the form: _Object X retains 11object Y, which is N bytes large, through its class member named Z_. 12 13Java heap dumps are not to be confused with profiles taken by the 14[Java heap sampler](native-heap-profiler.md#java-heap-sampling) 15 16## UI 17 18Heap graph dumps are shown as flamegraphs in the UI after clicking on the 19diamond in the _"Heap Profile"_ track of a process. Each diamond corresponds to 20a heap dump. 21 22 23 24 25 26The native size of certain objects is represented as an extra child node in the 27flamegraph, prefixed with "[native]". The extra node counts as an extra object. 28This is available only on Android 13 or higher. 29 30## SQL 31 32Information about the Java Heap is written to the following tables: 33 34* [`heap_graph_class`](/docs/analysis/sql-tables.autogen#heap_graph_class) 35* [`heap_graph_object`](/docs/analysis/sql-tables.autogen#heap_graph_object) 36* [`heap_graph_reference`](/docs/analysis/sql-tables.autogen#heap_graph_reference) 37 38`native_size` (available only on Android T+) is extracted from the related 39`libcore.util.NativeAllocationRegistry` and is not included in `self_size`. 40 41For instance, to get the bytes used by class name, run the following query. 42As-is this query will often return un-actionable information, as most of the 43bytes in the Java heap end up being primitive arrays or strings. 44 45```sql 46select c.name, sum(o.self_size) 47 from heap_graph_object o join heap_graph_class c on (o.type_id = c.id) 48 where reachable = 1 group by 1 order by 2 desc; 49``` 50 51|name |sum(o.self_size) | 52|--------------------|--------------------| 53|java.lang.String | 2770504| 54|long[] | 1500048| 55|int[] | 1181164| 56|java.lang.Object[] | 624812| 57|char[] | 357720| 58|byte[] | 350423| 59 60We can use `experimental_flamegraph` to normalize the graph into a tree, always 61taking the shortest path to the root and get cumulative sizes. 62Note that this is **experimental** and the **API is subject to change**. 63From this we can see how much memory is being held by each type of object 64 65For that, we need to find the timestamp and upid of the graph. 66 67```sql 68select distinct graph_sample_ts, upid from heap_graph_object 69``` 70 71graph_sample_ts | upid | 72--------------------|--------------------| 73 56785646801 | 1 | 74 75We can then use them to get the flamegraph data. 76 77```sql 78select name, cumulative_size 79 from experimental_flamegraph 80 where ts = 56785646801 81 and upid = 1 82 and profile_type = 'graph' 83 order by 2 desc; 84``` 85 86| name | cumulative_size | 87|------|-----------------| 88|java.lang.String|1431688| 89|java.lang.Class<android.icu.text.Transliterator>|1120227| 90|android.icu.text.TransliteratorRegistry|1119600| 91|com.android.systemui.statusbar.phone.StatusBarNotificationPresenter$2|1086209| 92|com.android.systemui.statusbar.phone.StatusBarNotificationPresenter|1085593| 93|java.util.Collections$SynchronizedMap|1063376| 94|java.util.HashMap|1063292| 95 96## TraceConfig 97 98The Java heap dump data source is configured through the 99[JavaHprofConfig](/docs/reference/trace-config-proto.autogen#JavaHprofConfig) 100section of the trace config. 101 102```protobuf 103data_sources { 104 config { 105 name: "android.java_hprof" 106 java_hprof_config { 107 process_cmdline: "com.google.android.inputmethod.latin" 108 dump_smaps: true 109 } 110 } 111} 112``` 113