Memory management: references not detached
See original GitHub issueContext
I am using swal2 in a heavy SPA that uses VueJs. I am currently busting all of the potential memory leakages in the application, and I believe I’ve found a potential threat coming from sweetalert2.
Current behavior
This problem occurs when you fire an alert using either a preConfirm
or by just attaching a function through .then()
, like so:
var baz = 4;
Swal.fire({
title: 'Test',
preConfirm: () => this.foo(baz)
}).then((d) => {
if (d.value) {
this.bar(baz)
}
})
It is important to note that this fire
method has been called inside a vuejs component, therefore the this
context of both foo
and bar
includes a whole bunch of data/properties/methods that may consumes a lot of memory.
If this swal modal is fired and the user cancel it (e.g. by clicking outside), the swal closes itself and everything works like a charm, except when you move out of the current vuejs
component, and take a quick look at a Chrome heap snapshot. Here is what I see :
We can clearly see that a WeakMap
inside sweetalert is retaining a Promise (I’m using bluebird promises btw, but it also happens without bluebird).
This promise seems to have all my vuejs
component attached as its context, preventing the GC from collecting the memory.
It is not an actual memory leak because the memory does not stack. It’s just an annoying reference that prevent the GC from collecting the underlying context.
Proposed solution
When going deeper using the debugger, I’ve identified the source of this behavior:
privateMethods
and privateProps
privateProps.promise
is retaining a promise with myvuejs
context.privateMethods.swalPromiseResolve
seems to retain avuejs
context as well.privateProps.innerParams
is retaining mypreConfirm
and therefore thevuejs
context attached to the function.privateProps.domCache
is retaining references a DetachedHtmlElement that can be seen in the heap snapshot. (less harmful but still)
Code
Here is my proposed solution : https://github.com/jf-m/sweetalert2/commit/b2a77c6639c8d5f7b18bc24d5a58c85b41bd5218
I have not made any pull-request because I am not sure wether removePopupAndResetState
is the right place to dispose of privateProps.innerParams
, privateProps.domCache
and privateMethods.swalPromiseResolve
…
However, I’ve tried my commit and the GC collects my vue components, is seems to work in my test case.
By the way, thank you for this amazing project, it’s saving me a huge amount of time in all my projects 😉 !
Cheers 🍺
Issue Analytics
- State:
- Created 4 years ago
- Reactions:1
- Comments:8 (8 by maintainers)
@limonte thanks for the PR! While trying to reproduce this, I was doing some other profiling and I could see that in some cases there are some detached DOM elements left by Swal (about 60 of them). I’ll double check with this PR as well and if my investigations confirm that I’ll open a new issue.
Thanks you so much @jf-m for the hard work! Sorry if I didn’t get to look at your changes yet, but I was a bit busy. I’ll try to review them as soon as possible!