blob: c9e57c48918e2b0232ccb3733dd497e199e1a385 [file] [log] [blame] [view]
hjd0304f112016-11-14 22:36:531# Heap Profiling with MemoryInfra
2
erikchenf98fd8c2018-02-01 19:55:553As of Chrome 48, MemoryInfra supports heap profiling. Chrome will track all live
4allocations (calls to new or malloc without a subsequent call to delete or free)
5along with sufficient metadata to identify the code that made the allocation.
hjd0304f112016-11-14 22:36:536
7[TOC]
8
erikchenf98fd8c2018-02-01 19:55:559## How to obtain a heap dump (M66+, Linux, macOS, Windows)
hjd0304f112016-11-14 22:36:5310
erikchenf98fd8c2018-02-01 19:55:5511 1. Navigate to chrome://flags and search for `memlog`.
hjd0304f112016-11-14 22:36:5312
erikchenf98fd8c2018-02-01 19:55:5513 2. Choose the process types you want to profile with the `memlog` flag. The
14 most common setting is `Only Browser`.
hjd0304f112016-11-14 22:36:5315
erikchenf98fd8c2018-02-01 19:55:5516 3. By default, small, infrequent allocations are omitted. If you want to see a
17 full heap dump, enable `memlog-keep-small-allocations`.
hjd0304f112016-11-14 22:36:5318
erikchenf98fd8c2018-02-01 19:55:5519 4. By default, stack traces use native stack traces, which does not contain any
20 thread information. To include the thread at time of allocation, set
21 `memlog-stack-mode` to `native with thread names`.
22
23 5. Restart Chrome.
24
25 6. Grab a [MemoryInfra][memory-infra] trace.
26
27 7. Save the trace.
28
erikchen005071b2018-08-30 20:07:3629 8. To symbolize the trace:
30 * Windows only: build `addr2line-pdb` from the chromium repository. For subsequent commands, add the flag `--addr2line-executable=<path_to_addr2lin-pdb>`
31 * If this is a local build, run the command `./third_party/catapult/tracing/bin/symbolize_trace --is-local-build <path_to_trace>`
32 * If this is an official Chrome build, run `./third_party/catapult/tracing/bin/symbolize_trace <path_to_trace>`. This will request authentication with google cloud storage to obtain symbol files [googlers only].
33 * If this is an official macOS or Linux Chrome build, add the flag `--use-breakpad-symbols`.
34 * If the trace is from a different device, add the flag `--only-symbolize-chrome-symbols`.
erikchenf98fd8c2018-02-01 19:55:5535
36 9. Turn off heap profiling in chrome://flags. Restart Chrome.
37
38 10. Load the (now symbolized) trace in chrome://tracing.
39
40## How to obtain a heap dump (M66+, Android)
41
42To obtain native heap dumps, you will need a custom build of Chrome with the GN
43arguments `enable_profiling = true`, `arm_use_thumb = false` and
44`symbol_level=1`. All other steps are the same.
45
46Alternatively, if you want to use an Official build of Chrome, navigate to
47chrome://flags and set `memlog-stack-mode` to `pseudo`. This will provide
48less-detailed stacks. The stacks also don't require symbolization.
49
50## How to obtain a heap dump (M65 and older)
51
52For the most part, the setting `enable-heap-profiling` in `chrome://flags` has a
53similar effect to the various `memlog` flags.
54
55
56## How to manually browse a heap dump
57
58 1. Select a heavy memory dump indicated by a purple ![M][m-purple] dot.
59
60 2. In the analysis view, cells marked with a triple bar icon (☰) contain heap
hjd0304f112016-11-14 22:36:5361 dumps. Select such a cell.
62
63 ![Cells containing a heap dump][cells-heap-dump]
64
erikchenf98fd8c2018-02-01 19:55:5565 3. Scroll down all the way to _Heap Details_.
hjd0304f112016-11-14 22:36:5366
erikchenfd7bb6c2018-03-22 18:04:1967 4. To navigate allocations, select a frame in the right-side pane and press
68 Enter/Return. To pop up the stack, press Backspace/Delete.
hjd0304f112016-11-14 22:36:5369
70[memory-infra]: README.md
71[m-purple]: https://storage.googleapis.com/chromium-docs.appspot.com/d7bdf4d16204c293688be2e5a0bcb2bf463dbbc3
72[cells-heap-dump]: https://storage.googleapis.com/chromium-docs.appspot.com/a24d80d6a08da088e2e9c8b2b64daa215be4dacb
73
erikchenf98fd8c2018-02-01 19:55:5574## How to automatically extract large allocations from a heap dump
hjd0304f112016-11-14 22:36:5375
erikchenf98fd8c2018-02-01 19:55:5576 1. Run `python ./third_party/catapult/experimental/tracing/bin/diff_heap_profiler.py
77 <path_to_trace>`
erikchenffe16492017-06-23 00:43:2778
erikchenf98fd8c2018-02-01 19:55:5579 2. This produces a directory `output`, which contains a JSON file.
erikchenffe16492017-06-23 00:43:2780
erikchenf98fd8c2018-02-01 19:55:5581 3. Load the contents of the JSON file in any JSON viewer, e.g.
82 [jsonviewer](http://jsonviewer.stack.hu/).
erikchenffe16492017-06-23 00:43:2783
erikchenf98fd8c2018-02-01 19:55:5584 4. The JSON files shows allocations segmented by stacktrace, sorted by largest
85 first.
hjd0304f112016-11-14 22:36:5386
87## Heap Details
88
89The heap details view contains a tree that represents the heap. The size of the
90root node corresponds to the selected allocator cell.
91
92*** aside
93The size value in the heap details view will not match the value in the selected
94analysis view cell exactly. There are three reasons for this. First, the heap
95profiler reports the memory that _the program requested_, whereas the allocator
96reports the memory that it _actually allocated_ plus its own bookkeeping
97overhead. Second, allocations that happen early --- before Chrome knows that
98heap profiling is enabled --- are not captured by the heap profiler, but they
99are reported by the allocator. Third, tracing overhead is not discounted by the
100heap profiler.
101***
102
103The heap can be broken down in two ways: by _backtrace_ (marked with an ƒ), and
104by _type_ (marked with a Ⓣ). When tracing is enabled, Chrome records trace
105events, most of which appear in the flame chart in timeline view. At every
106point in time these trace events form a pseudo stack, and a vertical slice
107through the flame chart is like a backtrace. This corresponds to the ƒ nodes in
108the heap details view. Hence enabling more tracing categories will give a more
109detailed breakdown of the heap.
110
111The other way to break down the heap is by object type. At the moment this is
112only supported for PartitionAlloc.
113
114*** aside
115In official builds, only the most common type names are included due to binary
116size concerns. Development builds have full type information.
117***
118
119To keep the trace log small, uninteresting information is omitted from heap
120dumps. The long tail of small nodes is not dumped, but grouped in an `<other>`
qyearsleyc0dc6f42016-12-02 22:13:39121node instead. Note that although these small nodes are insignificant on their
hjd0304f112016-11-14 22:36:53122own, together they can be responsible for a significant portion of the heap. The
123`<other>` node is large in that case.
124
125## Example
126
127In the trace below, `ParseAuthorStyleSheet` is called at some point.
128
129![ParseAuthorStyleSheet pseudo stack][pseudo-stack]
130
131The pseudo stack of trace events corresponds to the tree of ƒ nodes below. Of
132the 23.5 MiB of memory allocated with PartitionAlloc, 1.9 MiB was allocated
133inside `ParseAuthorStyleSheet`, either directly, or at a deeper level (like
134`CSSParserImpl::parseStyleSheet`).
135
136![Memory Allocated in ParseAuthorStyleSheet][break-down-by-backtrace]
137
138By expanding `ParseAuthorStyleSheet`, we can see which types were allocated
139there. Of the 1.9 MiB, 371 KiB was spent on `ImmutableStylePropertySet`s, and
140238 KiB was spent on `StringImpl`s.
141
142![ParseAuthorStyleSheet broken down by type][break-down-by-type]
143
144It is also possible to break down by type first, and then by backtrace. Below
145we see that of the 23.5 MiB allocated with PartitionAlloc, 1 MiB is spent on
146`Node`s, and about half of the memory spent on nodes was allocated in
147`HTMLDocumentParser`.
148
149![The PartitionAlloc heap broken down by type first and then by backtrace][type-then-backtrace]
150
151Heap dump diffs are fully supported by trace viewer. Select a heavy memory dump
152(a purple dot), then with the control key select a heavy memory dump earlier in
153time. Below is a diff of theverge.com before and in the middle of loading ads.
154We can see that 4 MiB were allocated when parsing the documents in all those
155iframes, almost a megabyte of which was due to JavaScript. (Note that this is
156memory allocated by PartitionAlloc alone, the total renderer memory increase was
157around 72 MiB.)
158
159![Diff of The Verge before and after loading ads][diff]
160
161[pseudo-stack]: https://storage.googleapis.com/chromium-docs.appspot.com/058e50350836f55724e100d4dbbddf4b9803f550
162[break-down-by-backtrace]: https://storage.googleapis.com/chromium-docs.appspot.com/ec61c5f15705f5bcf3ca83a155ed647a0538bbe1
163[break-down-by-type]: https://storage.googleapis.com/chromium-docs.appspot.com/2236e61021922c0813908c6745136953fa20a37b
164[type-then-backtrace]: https://storage.googleapis.com/chromium-docs.appspot.com/c5367dde11476bdbf2d5a1c51674148915573d11
165[diff]: https://storage.googleapis.com/chromium-docs.appspot.com/802141906869cd533bb613da5f91bd0b071ceb24