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