| OLD | NEW | 
|    1 # Heap Profiling with MemoryInfra |    1 This document has moved to [//docs/memory-infra/heap_profiler.md](/docs/memory-i
     nfra/heap_profiler.md). | 
|    2  |    2  | 
|    3 As of Chrome 48, MemoryInfra supports heap profiling. The core principle is |  | 
|    4 a solution that JustWorks™ on all platforms without patching or rebuilding, |  | 
|    5 intergrated with the chrome://tracing ecosystem. |  | 
|    6  |  | 
|    7 [TOC] |  | 
|    8  |  | 
|    9 ## How to Use |  | 
|   10  |  | 
|   11  1. Start Chrome with the `--enable-heap-profiling` switch. This will make |  | 
|   12     Chrome keep track of all allocations. |  | 
|   13  |  | 
|   14  2. Grab a [MemoryInfra][memory-infra] trace. For best results, start tracing |  | 
|   15     first, and _then_ open a new tab that you want to trace. Furthermore, |  | 
|   16     enabling more categories (besides memory-infra) will yield more detailed |  | 
|   17     information in the heap profiler backtraces. |  | 
|   18  |  | 
|   19  3. When the trace has been collected, select a heavy memory dump indicated by |  | 
|   20     a purple ![M][m-purple] dot. Heap dumps are only included in heavy memory |  | 
|   21     dumps. |  | 
|   22  |  | 
|   23  4. In the analysis view, cells marked with a triple bar icon (☰) contain heap |  | 
|   24     dumps. Select such a cell. |  | 
|   25  |  | 
|   26       ![Cells containing a heap dump][cells-heap-dump] |  | 
|   27  |  | 
|   28  5. Scroll down all the way to _Heap Details_. |  | 
|   29  |  | 
|   30  6. Pinpoint the memory bug and live happily ever after. |  | 
|   31  |  | 
|   32 [memory-infra]:    memory_infra.md |  | 
|   33 [m-purple]:        https://storage.googleapis.com/chromium-docs.appspot.com/d7bd
     f4d16204c293688be2e5a0bcb2bf463dbbc3 |  | 
|   34 [cells-heap-dump]: https://storage.googleapis.com/chromium-docs.appspot.com/a24d
     80d6a08da088e2e9c8b2b64daa215be4dacb |  | 
|   35  |  | 
|   36 ### Native stack traces |  | 
|   37  |  | 
|   38 By default heap profiling collects pseudo allocation traces, which are based |  | 
|   39 on trace events. I.e. frames in allocation traces correspond to trace events |  | 
|   40 that were active at the time of allocations, and are not real function names. |  | 
|   41 However, you can build a special Linux / Android build that will collect |  | 
|   42 real C/C++ stack traces. |  | 
|   43  |  | 
|   44  1. Build with the following GN flags: |  | 
|   45  |  | 
|   46         Linux |  | 
|   47  |  | 
|   48         enable_profiling = true |  | 
|   49  |  | 
|   50  |  | 
|   51         Android |  | 
|   52  |  | 
|   53         arm_use_thumb = false |  | 
|   54         enable_profiling = true |  | 
|   55  |  | 
|   56  2. Start Chrome with `--enable-heap-profiling=native` switch (notice |  | 
|   57         `=native` part). |  | 
|   58  |  | 
|   59         On Android use the command line tool before starting the app: |  | 
|   60  |  | 
|   61         build/android/adb_chrome_public_command_line --enable-heap-profiling=nat
     ive |  | 
|   62  |  | 
|   63         (run the tool with an empty argument `''` to clear the command line) |  | 
|   64  |  | 
|   65  3. Grab a [MemoryInfra][memory-infra] trace. You don't need any other |  | 
|   66         categories besides `memory-infra`. |  | 
|   67  |  | 
|   68  4. Save the grabbed trace file. This step is needed because freshly |  | 
|   69         taken trace file contains raw addresses (which look like `pc:dcf5dbf8`) |  | 
|   70         instead of function names, and needs to be symbolized. |  | 
|   71  |  | 
|   72  4. Symbolize the trace file. During symbolization addresses are resolved to |  | 
|   73         the corresponding function names and trace file is rewritten (but a back
     up |  | 
|   74         is saved with `.BACKUP` extension). |  | 
|   75  |  | 
|   76         Linux |  | 
|   77  |  | 
|   78         third_party/catapult/tracing/bin/symbolize_trace <trace file> |  | 
|   79  |  | 
|   80         Android |  | 
|   81  |  | 
|   82         third_party/catapult/tracing/bin/symbolize_trace --output-directory out/
     Release <trace file> |  | 
|   83  |  | 
|   84         (note `--output-directory` and make sure it's right for your setup) |  | 
|   85  |  | 
|   86  5. Load the trace file in `chrome://tracing`. Locate a purple ![M][m-purple] |  | 
|   87         dot, and continue from step *3* from the instructions above. Native stac
     k |  | 
|   88         traces will be shown in the _Heap Details_ pane. |  | 
|   89  |  | 
|   90 ## Heap Details |  | 
|   91  |  | 
|   92 The heap details view contains a tree that represents the heap. The size of the |  | 
|   93 root node corresponds to the selected allocator cell. |  | 
|   94  |  | 
|   95 *** aside |  | 
|   96 The size value in the heap details view will not match the value in the selected |  | 
|   97 analysis view cell exactly. There are three reasons for this. First, the heap |  | 
|   98 profiler reports the memory that _the program requested_, whereas the allocator |  | 
|   99 reports the memory that it _actually allocated_ plus its own bookkeeping |  | 
|  100 overhead. Second, allocations that happen early --- before Chrome knows that |  | 
|  101 heap profiling is enabled --- are not captured by the heap profiler, but they |  | 
|  102 are reported by the allocator. Third, tracing overhead is not discounted by the |  | 
|  103 heap profiler. |  | 
|  104 *** |  | 
|  105  |  | 
|  106 The heap can be broken down in two ways: by _backtrace_ (marked with an ƒ), and |  | 
|  107 by _type_ (marked with a Ⓣ). When tracing is enabled, Chrome records trace |  | 
|  108 events, most of which appear in the flame chart in timeline view. At every |  | 
|  109 point in time these trace events form a pseudo stack, and a vertical slice |  | 
|  110 through the flame chart is like a backtrace. This corresponds to the ƒ nodes in |  | 
|  111 the heap details view.  Hence enabling more tracing categories will give a more |  | 
|  112 detailed breakdown of the heap. |  | 
|  113  |  | 
|  114 The other way to break down the heap is by object type. At the moment this is |  | 
|  115 only supported for PartitionAlloc. |  | 
|  116  |  | 
|  117 *** aside |  | 
|  118 In official builds, only the most common type names are included due to binary |  | 
|  119 size concerns. Development builds have full type information. |  | 
|  120 *** |  | 
|  121  |  | 
|  122 To keep the trace log small, uninteresting information is omitted from heap |  | 
|  123 dumps. The long tail of small nodes is not dumped, but grouped in an `<other>` |  | 
|  124 node instead. Note that altough these small nodes are insignificant on their |  | 
|  125 own, together they can be responsible for a significant portion of the heap. The |  | 
|  126 `<other>` node is large in that case. |  | 
|  127  |  | 
|  128 ## Example |  | 
|  129  |  | 
|  130 In the trace below, `ParseAuthorStyleSheet` is called at some point. |  | 
|  131  |  | 
|  132 ![ParseAuthorStyleSheet pseudo stack][pseudo-stack] |  | 
|  133  |  | 
|  134 The pseudo stack of trace events corresponds to the tree of ƒ nodes below. Of |  | 
|  135 the 23.5 MiB of memory allocated with PartitionAlloc, 1.9 MiB was allocated |  | 
|  136 inside `ParseAuthorStyleSheet`, either directly, or at a deeper level (like |  | 
|  137 `CSSParserImpl::parseStyleSheet`). |  | 
|  138  |  | 
|  139 ![Memory Allocated in ParseAuthorStyleSheet][break-down-by-backtrace] |  | 
|  140  |  | 
|  141 By expanding `ParseAuthorStyleSheet`, we can see which types were allocated |  | 
|  142 there. Of the 1.9 MiB, 371 KiB was spent on `ImmutableStylePropertySet`s, and |  | 
|  143 238 KiB was spent on `StringImpl`s. |  | 
|  144  |  | 
|  145 ![ParseAuthorStyleSheet broken down by type][break-down-by-type] |  | 
|  146  |  | 
|  147 It is also possible to break down by type first, and then by backtrace. Below |  | 
|  148 we see that of the 23.5 MiB allocated with PartitionAlloc, 1 MiB is spent on |  | 
|  149 `Node`s, and about half of the memory spent on nodes was allocated in |  | 
|  150 `HTMLDocumentParser`. |  | 
|  151  |  | 
|  152 ![The PartitionAlloc heap broken down by type first and then by backtrace][type-
     then-backtrace] |  | 
|  153  |  | 
|  154 Heap dump diffs are fully supported by trace viewer. Select a heavy memory dump |  | 
|  155 (a purple dot), then with the control key select a heavy memory dump earlier in |  | 
|  156 time. Below is a diff of theverge.com before and in the middle of loading ads. |  | 
|  157 We can see that 4 MiB were allocated when parsing the documents in all those |  | 
|  158 iframes, almost a megabyte of which was due to JavaScript. (Note that this is |  | 
|  159 memory allocated by PartitionAlloc alone, the total renderer memory increase was |  | 
|  160 around 72 MiB.) |  | 
|  161  |  | 
|  162 ![Diff of The Verge before and after loading ads][diff] |  | 
|  163  |  | 
|  164 [pseudo-stack]:            https://storage.googleapis.com/chromium-docs.appspot.
     com/058e50350836f55724e100d4dbbddf4b9803f550 |  | 
|  165 [break-down-by-backtrace]: https://storage.googleapis.com/chromium-docs.appspot.
     com/ec61c5f15705f5bcf3ca83a155ed647a0538bbe1 |  | 
|  166 [break-down-by-type]:      https://storage.googleapis.com/chromium-docs.appspot.
     com/2236e61021922c0813908c6745136953fa20a37b |  | 
|  167 [type-then-backtrace]:     https://storage.googleapis.com/chromium-docs.appspot.
     com/c5367dde11476bdbf2d5a1c51674148915573d11 |  | 
|  168 [diff]:                    https://storage.googleapis.com/chromium-docs.appspot.
     com/802141906869cd533bb613da5f91bd0b071ceb24 |  | 
| OLD | NEW |