• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
56```sql
57select name, cumulative_size
58       from experimental_flamegraph(56785646801, 1, 'graph')
59       order by 2 desc;
60```
61
62| name | cumulative_size |
63|------|-----------------|
64|java.lang.String|1431688|
65|java.lang.Class<android.icu.text.Transliterator>|1120227|
66|android.icu.text.TransliteratorRegistry|1119600|
67|com.android.systemui.statusbar.phone.StatusBarNotificationPresenter$2|1086209|
68|com.android.systemui.statusbar.phone.StatusBarNotificationPresenter|1085593|
69|java.util.Collections$SynchronizedMap|1063376|
70|java.util.HashMap|1063292|
71
72## TraceConfig
73
74The Java heap profiler is configured through the
75[JavaHprofConfig](/docs/reference/trace-config-proto.autogen#JavaHprofConfig)
76section of the trace config.
77
78```protobuf
79data_sources {
80  config {
81    name: "android.java_hprof"
82    java_hprof_config {
83      process_cmdline: "com.google.android.inputmethod.latin"
84      dump_smaps: true
85    }
86  }
87}
88```
89