Windows
Windows
Any sufficiently large web application will probably reach the point where it uses more memory than expected. At that point, a developer might start recording in DevTools to investigate what objects are contained in memory. For any object listed in the snapshot, DevTools shows, in the Retainers pane, what other objects cause it to remain in memory. Any object with no retainers can be discarded by the browser’s garbage collector, which reduces memory usage. However, the Retainers pane is only useful if it works correctly. Over the past several months, we have received several excellent bug reports from Microsoft Teams engineers describing cases where DevTools showed retainers that simply made no sense, and there was no way that a web application developer could take any action to remove those retainers. Thank you to everyone who brought these issues to our attention. We’ve fixed those bugs (details below), but of course there may be others, so if you see something that seems wrong, please speak up! The easiest way to get in touch is the feedback button in the devtools: Before we get started, note that although several things below refer to Microsoft Edge, the problems we fixed were in the browser’s JavaScript engine’s code (V8). This code is shared with Chrome, Electron, Node, and others, so all those products will benefit from the fixes.
Swimming in false retainer paths
Suppose you were working on the Microsoft Edge new-tab page (edge://newtab) and wanted to know why the function namedobserve() is being kept alive. You would hit F12 to open DevTools, navigate to the Memory tab, and select the relevant object in the top pane. In Microsoft Edge version 94, you would see four retainers for that function: The shortest path goes through a FeedbackVector, an internal data type which collects data about what functions have been called by another function. Expanding that path a little more, you would see that the FeedbackVector is owned by another function, HTMLElement.attachShadow(): So, there’s this function which retains some internal V8 goo that you have no control over which, in turn, retains the original function observe(). How can you possibly break that link, since it’s all V8 internals? You can’t, which means there’s a bug. Either V8 is leaking memory, or the Retainers pane is incorrect, and both are serious high-priority issues for us. In this case, the problem was that Microsoft Edge showed incorrect retainers. We have fixed this issue in Microsoft Edge 99. Here is the correct answer list of retainers: Because the Retainers tree is both deep and wide on large apps, the number of false paths completely blocked many memory usage investigations. This problem was so pervasive that our friends at Microsoft Teams have been using a workaround which captures additional information during V8’s garbage collection phase and highlights a single retainer path which is actually known to be true.