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