|  | 1 | = Investigating Leaks and Bloat = | 
          
            |  | 2 | ''by Simon Fraser'' | 
          
            |  | 3 |  | 
          
            |  | 4 | - Or… a bunch of half-baked memory tools | 
          
            |  | 5 | - Or… don’t be afraid to change code to collect data | 
          
            |  | 6 | - Don’t be scared to do this | 
          
            |  | 7 |  | 
          
            |  | 8 | - Starting problem | 
          
            |  | 9 | - “WebContent physical footprint doesn’t go back down significantly after going from nytimes.com to a simple page (about:blank)” | 
          
            |  | 10 | - When we say memory use is too high we look at Physical Footprint metric | 
          
            |  | 11 | - When measuring memory: Beware of caches | 
          
            |  | 12 | - Proper steps | 
          
            |  | 13 | - Load about:blank | 
          
            |  | 14 | - Get physical footprint with `vmmap` | 
          
            |  | 15 | - Load nytimes.com | 
          
            |  | 16 | - Go back to about:blank | 
          
            |  | 17 | - Fire memory warning | 
          
            |  | 18 | - Get physical footprint with `vmmap` | 
          
            |  | 19 | - “Something is not going away” | 
          
            |  | 20 | - Leaks? | 
          
            |  | 21 | - Tool called “leaks”: `leaks <pid>` | 
          
            |  | 22 | - Adding Quick & Easy “State of the world” Data Gathering | 
          
            |  | 23 | - Handy too on Mac | 
          
            |  | 24 | - `notifyutil -p` | 
          
            |  | 25 | - Broadcasts notifications to processes, processes can register handlers | 
          
            |  | 26 | - Handles: | 
          
            |  | 27 | - org.WebKit.lowMemory | 
          
            |  | 28 | - com.apple.WebKit.fullGC | 
          
            |  | 29 | - com.apple.WebKit.deleteAllCode | 
          
            |  | 30 | - com.apple.WebKit.Cache.dump | 
          
            |  | 31 | - com.apple.WebKit.showAllDocuments* | 
          
            |  | 32 | - com.apple.WebKit.showMemoryCache* | 
          
            |  | 33 | - com.apple.WebKit.showPageCache* | 
          
            |  | 34 | - * added in last 6 months | 
          
            |  | 35 | - `notifyutil -p com.apple.WebKit.showAllDocuments` | 
          
            |  | 36 | - Why aren’t they leaks? | 
          
            |  | 37 | - Leaks tool looks for rooted graphs of objects | 
          
            |  | 38 | - This is really “Abandonment” or “leaks” | 
          
            |  | 39 | - So what objects are hanging around? | 
          
            |  | 40 | - Object Counters | 
          
            |  | 41 | - Is this a JS heap issue, or a C++ ref-counting issue? | 
          
            |  | 42 | - Which world is the issue happening in? | 
          
            |  | 43 | - Not always easy to tell | 
          
            |  | 44 | - Do the JS* objects go away? | 
          
            |  | 45 | - Did all the doc nodes get destroyed? | 
          
            |  | 46 | - `notifyutil -p com.apple.WebKit.showAllDocuments` | 
          
            |  | 47 | - Look at referencingNodeCount | 
          
            |  | 48 | - JS Heap | 
          
            |  | 49 | - GC | 
          
            |  | 50 | - Visist s every object that JS knows about (as JSCell*), starting at GC roots | 
          
            |  | 51 | - JSC::Heap, JSC::SlotVisitor, visistChildren() methods | 
          
            |  | 52 | - Unvisisted objects can be GC | 
          
            |  | 53 | - Doesn’t care about unrooted cycles | 
          
            |  | 54 | - GC Heap Inspector | 
          
            |  | 55 | - Heap Snapshots in Web Inspector | 
          
            |  | 56 | - Not quite enough info, no C++ pointer objects | 
          
            |  | 57 | - `notifyutil -p com.apple.WebKit.dumpGCHeap` | 
          
            |  | 58 | - Checked-in: https://trac.webkit.org/r235271 | 
          
            |  | 59 | - GC-related Document Leaks | 
          
            |  | 60 | - DFG Scratch buffer | 
          
            |  | 61 | - Exception backtraces | 
          
            |  | 62 | - VM lastException | 
          
            |  | 63 | - JSPerformanceObserverCallback: Strong<Function> | 
          
            |  | 64 | - Strong references indicate GC problems | 
          
            |  | 65 | - C++ leaks | 
          
            |  | 66 | - Unbalanced ref()/deref(), retain reference cycles | 
          
            |  | 67 | - `refCount 1` indicates a C++ leak | 
          
            |  | 68 | - Ref tracking | 
          
            |  | 69 | - Collate matching ref() and deref() via “tokens” | 
          
            |  | 70 | - Ref Token Tracking | 
          
            |  | 71 | - Fix Ref<> and RefPtr<> to store tokens | 
          
            |  | 72 | - All ref() and deref() via  Ref<> and RefPtr<> are tracked | 
          
            |  | 73 | - RefTracker class example | 
          
            |  | 74 | - Call stack records the ref | 
          
            |  | 75 | - StackShot is your friend | 
          
            |  | 76 | - Wrapper for WTFGetBacktrace() | 
          
            |  | 77 | - Washable | 
          
            |  | 78 | - Great for “accumulate all the calls stacks that did this thing” | 
          
            |  | 79 | - Controllable stack depth | 
          
            |  | 80 | - TrackedRefCounted<> | 
          
            |  | 81 | - Dumping Unmatched Refs | 
          
            |  | 82 | - `RefTracker::dumpRemainingReferences()` | 
          
            |  | 83 | - RefTracker is powerful! | 
          
            |  | 84 | - Sometimes dumps the only unmatched `ref()` callstack! | 
          
            |  | 85 | - Easy to patch up manual `ref()`/`deref()` code paths by tracking RefTrackingTokens | 
          
            |  | 86 | - webkit.org/b.186269 (reviewz plz) | 
          
            |  | 87 | - Make it possible to track unbalanced ref()/deref() | 
          
            |  | 88 | - RefTracker on Node | 
          
            |  | 89 | - Give Node a RefTracker | 
          
            |  | 90 | - Tracks Nodes, Elements, Documents | 
          
            |  | 91 | - Now we can track Document refs | 
          
            |  | 92 | - Hack the “com.apple.WebKit.showAllDocuments” callback to dump ref stacks for live Documents | 
          
            |  | 93 | - You can turn it on and its not a huge perf hit | 
          
            |  | 94 | - Making leaks not happen again | 
          
            |  | 95 | - Used GCHeap Inspector | 
          
            |  | 96 | - Fixed a leak | 
          
            |  | 97 | - “Finding a regression in EWS is 1000x more efficient than finding it via a perf benchmark regression” — Simon Fraser | 
          
            |  | 98 | - webkit.org/b/186214 | 
          
            |  | 99 | - Isn’t this like the old “world leaks”? | 
          
            |  | 100 | - Sort of is… | 
          
            |  | 101 | - Leaks of world-level objects | 
          
            |  | 102 | - Checking for Leaks in Testing | 
          
            |  | 103 | - `./Tools/Scripts/run-webkit-tests --world-leaks` | 
          
            |  | 104 | - How it Works | 
          
            |  | 105 | - After each test | 
          
            |  | 106 | - WKBundleGetLiveDocumentURLs() | 
          
            |  | 107 | - Implications for run-webkit-tests | 
          
            |  | 108 | - New failure type: “LEAK” | 
          
            |  | 109 | - “LEAK” only relevant if you ran with `--world-leaks` | 
          
            |  | 110 | - Leak checking is post-hoc | 
          
            |  | 111 | - A test can pass, and then become a leak failure | 
          
            |  | 112 | - Remaining Work | 
          
            |  | 113 | - Add LEAK expectations for all platforms | 
          
            |  | 114 | - Fix the causes of most common document leaks | 
          
            |  | 115 | - Fix causes of false Leaks | 
          
            |  | 116 | - Turn on by default | 
          
            |  | 117 | - C++ Document Leaks | 
          
            |  | 118 | - Web Animations | 
          
            |  | 119 | - Document::removeFocusNavigationNodeofSubtree() | 
          
            |  | 120 | - Content Filtering | 
          
            |  | 121 | - IndexedDB | 
          
            |  | 122 | - SVG text tests | 
          
            |  | 123 | - WebFullScreenManager | 
          
            |  | 124 | - C++ Document Lifetime Extenders | 
          
            |  | 125 | - NavigationAction | 
          
            |  | 126 | - Editor/Selection | 
          
            |  | 127 | - ServicesOverlayController | 
          
            |  | 128 | - DragController | 
          
            |  | 129 | - To Do | 
          
            |  | 130 | - When WebKitTestRunner detects a leak: | 
          
            |  | 131 | - Dump unmatched refs when tests detect a leak | 
          
            |  | 132 | - Dump a GC heap | 
          
            |  | 133 | - Some auto analysis? | 
          
            |  | 134 | - Halp | 
          
            |  | 135 | - webkit.org/b/186214 | 
          
            |  | 136 | - Now the memory problems are solved, right? | 
          
            |  | 137 | - Not really, still some issues in vmmap | 
          
            |  | 138 | - MALLOC zones | 
          
            |  | 139 | - Dirty size column is interesting, WebKit MALLOC (411 MB) | 
          
            |  | 140 | - “Where does all the memory go?” | 
          
            |  | 141 | - webkit.org/b/186422 Create lots of different malloc zones for easier accounting of memory use | 
          
            |  | 142 | - Created custom MALLOC zones for WebKit | 
          
            |  | 143 | - Big ones | 
          
            |  | 144 | - Vector capacity | 
          
            |  | 145 | - HashTable | 
          
            |  | 146 | - webkit.org/b/186698 Make it possible to track all sites that waste container capacity | 
          
            |  | 147 | - Container Capacity Tracking | 
          
            |  | 148 | - Give the Vector/HashTable an ID (can’t track by address) | 
          
            |  | 149 | - Record allocation with a StackShot | 
          
            |  | 150 | - On deallocation remove the record | 
          
            |  | 151 | - Dump living capacity: | 
          
            |  | 152 | - Aggregate by StackShot | 
          
            |  | 153 | - Sort by most to least wasteful | 
          
            |  | 154 | - Consider not using as many HashTables? | 
          
            |  | 155 | - Maybe use different types of tables? | 
          
            |  | 156 | - Memory Reduction | 
          
            |  | 157 | - bmalloc space efficiency | 
          
            |  | 158 | - Maybe as good as system malloc? Problem if using both, using one is fine | 
          
            |  | 159 | - JSC optimizations for space efficiency (even with the JIT) | 
          
            |  | 160 | - WebCore optimizations for space efficiency | 
          
            |  | 161 | - Review Vector and HashTable growth policies | 
          
            |  | 162 | - Resiable hashes (Robin Hood hashing?) | 
          
            |  | 163 | - Vector shrinking | 
          
            |  | 164 | - Convert from HashMaps and HashSets to other data structures | 
          
            |  | 165 | - Adjust caching policies | 
          
            |  | 166 | - Better Low Memory Handler | 
          
            |  | 167 | - Don’t dirty more pages than you release | 
          
            |  | 168 | - Organize data structures to release memory without visiting pages | 
          
            |  | 169 | - More use of purgeable memory | 
          
            |  | 170 | - WebProcess watermark (big 2.5 GB?) | 
          
            |  | 171 | - Space-Efficient Class Layout | 
          
            |  | 172 | - Micro-optimization? | 
          
            |  | 173 | - `dump-class-layout -c Release WebCore FillLayer` | 
          
            |  | 174 | - Look for `<Padding: n bytes>` entries | 
          
            |  | 175 | - Also look at `<UNUSED BITS: n bits>` | 
          
            |  | 176 | - std::optional causes these to get big | 
          
            |  | 177 | - There’s been work on different optional types | 
          
            |  | 178 | - Optional with a magic value (doesn’t waste any space) | 
          
            |  | 179 | - Patch for a set of optionals in a bit field | 
          
            |  | 180 | - Beware of enums | 
          
            |  | 181 | - For enums, you should specify size | 
          
            |  | 182 | - Big Stuff | 
          
            |  | 183 | - Don’t just use all available memory | 
          
            |  | 184 | - Manage cache sizes | 
          
            |  | 185 | - Cache budgets | 
          
            |  | 186 | - JS Heap size | 
          
            |  | 187 | - Don’t Cause Leaks | 
          
            |  | 188 | - Be careful with JS bindings code | 
          
            |  | 189 | - JSC::strong<> is almost always wrong | 
          
            |  | 190 | - Be careful with holding refs to Documents, elements | 
          
            |  | 191 | - Avoid cycles | 
          
            |  | 192 | - Avoid extending object lifetimes | 
          
            |  | 193 | - Don’t write floaty classes | 
          
            |  | 194 | - Shrink vectors, avoid unused inline capacity on heap-allocated objects | 
          
            |  | 195 | - Do you really need to use HashTable? | 
          
            |  | 196 | - Beware enums and std::optionals | 
          
            |  | 197 | - Look for Leaks | 
          
            |  | 198 | - Tools for investigating Leaks | 
          
            |  | 199 | - cCache dumping | 
          
            |  | 200 | - GC heap inspector | 
          
            |  | 201 | - Ref token tracking |