The nextState() function is causing memory leaks. The nextState() is called on every link interaction many times. Each link interaction is causing the Popups extension to trigger "show popup logic", which triggers nextState() calls. Instead of using Object.assign() we decided to implemenet our own nextState() function because of lack of the IE support.
The main problem is that the state object contains not only scalar types, it also contains:
- objects
- baseData: {pageTitleSource: "PageA", namespaceIdSource: 0, pageIdSource: 5, isAnon: true, popupEnabled: true, …}
- event: {action: "pageLoaded"}
- interaction: {link: a, title: "PHP", namespaceId: 0, token: "e5db2f5fcd8e584869b1", started: 1543961297316, …}
- jQuery events activeEvent: jQuery.Event {originalEvent: MouseEvent, type: "mouseover", isDefaultPrevented: ƒ, target: a, currentTarget: a, …}
- dom nodes:
- activeLink: a
- link: a
I ran some tests with using our existing nextState() and with Object.assign() method. Object.assign() causes a smaller memory footprint. In general when Object.assign() was used Garbage Collector was able to free more memory.
For example, after ~3 minutes of interacting with Page previews (tests were executed multiple times):
nextState: JS memory heap increased by 0.8MB, ~1000 objects stored in memory Object.assign(): JS memory heap increased by 0.5-0.6MB, ~200 objects stored in the memory.
Developer notes
- ResourceLoader supports skipFunction which can be used to provide an Object.Assign() polyfill
- We should not store DOM elements in the store, as those also might cause memory leaks (not properly disposed). Please verify is it possible to not store the activeLink or link in the state.
- Popups' dependencies are quite outdated, some by major versions. It may be useful to try upgrading these to see if it affects the leak.