-
Notifications
You must be signed in to change notification settings - Fork 120
Memory leaks
After investigating some memory leaks the following are some helpfull tips on how best to find memory leaks.
Linking @elastic/charts
to kibana can surface memory leaks that may not be present in our storybook
so keep this in mind when investigating leaks and deciding when to link via yarn link:kibana
.
The incognito browser disables most if not all extensions that they themselves could have memory leaks and create misleading noise in the memory heap snapshot.
The redux dev tools extension can create noice when looking at the heap snapshot so it's best to remove this during your investigation. See packages/charts/src/components/chart.tsx
for code below.
const getMiddlware = (id: string): StoreEnhancer => {
const middlware: Middleware<any, any, any>[] = [];
// if (typeof window !== 'undefined' && (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) {
// // eslint-disable-next-line @typescript-eslint/no-unsafe-call
// return (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({
// trace: true,
// name: `@elastic/charts (id: ${id})`,
// })(applyMiddleware(...middlware));
// }
return applyMiddleware(...middlware);
};
Before generating a detailed heap snapshot, memory leaks can be identified using Chrome's performance monitor tool. One red flag with respect to DOM elements is an ever-increasing node count where even with garbage collection the DOM node count continues to grow for a given action.
Notice the green series representing node count, always increases. A normal chart would look like a sawtooth shape with increases and decreases as garbage collections removes unneeded DOM nodes.
See short demo here
The heap snapshot is one of three options for exploring the memory usage in Chrome. The best use of this is to preform some series of actions that are causing memory issues, then take the snapshot. Click the garbage collection icon is a good practice to force garbae collection before the snapshot is taken.
Once the snapshot is loaded, the best way to search for detached DOM nodes is to filter for Detached
nodes in the top filter. Focus on the top item groups that have the highest RetainedSize
that have the same order of magnitude, in the case below this would be the top three.
Once you have identified the items of concern, we can look at each of the items by expanding the tree to find the culprit that is retaining a reference to the detached DOM node, again focusing on the items with that largest retained size.
Selecting the first element under the top-level constructor will show what is actually retaining a reference to the detached DOM node. The tree will automatically expand to the exact retainer. This can tend to be a lot of information overload but the key is to look for signs of code that is familier to you. In the examples below it seems the main culprit is getSettingsSpecSelector
and the _cache
object used in the FlatObjectCache
class by re-reselect
.
From here we have identified one source of a potential memory leak, we could continue to repeat this tree exploration for other top-level items in the tree to see what other parts of our code could be retaining references to detached DOM nodes or provide more clues to the same issue we already discovered above.
Hovering over the filename, where applicable, will show you where the code is coming from to better locate and indenfiy which issues to focus on and which to ignore. Clicking the link will redirect you to the file source code in the sources
tab.
Hovering over the memory address (i.g. @1650201
) will show the object preview at that address to dig deeper into the state of the code at a paticular time. This again can be helpful to decide what issues to ignore. These previews are not always available especially when refreshing the page after taking the snapshot, if you desire this ability I would advise taking another snapshot without refreshing the page.