Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Patch memory leaks caused by event handlers bound to document #9337

Closed
wants to merge 4 commits into from

Conversation

arindam1993
Copy link
Contributor

@arindam1993 arindam1993 commented Feb 24, 2020

This potentially addresses #9126.

We temporarily bind handlers to document in our event handlers when certain interactions are in flight. If the map is removed during that time, it causes the entire Map object to be retained, since its in the scope of the event handlers.

<changelog>Fixed a memory leak that occurred if the map was removed while certain user interactions were in progress.</changelog>

@arindam1993 arindam1993 requested a review from kkaefer February 24, 2020 22:52
@iamanvesh
Copy link

Hi @arindam1993,
I've tried using the build from this branch with the sample code that I provided in #9126 (jsbin without react) and I don't see any improvement in memory usage. It's still retaining a lot of memory in Safari.

@arindam1993
Copy link
Contributor Author

@iamanvesh I posted some results from some digging in #9126 , could we continue the conversation there?

window.document.removeEventListener('mousemove', this._onMouseMove, false);
window.document.removeEventListener('keydown', this._onKeyDown, false);
window.document.removeEventListener('mouseup', this._onMouseUp, false);
}

teardown() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the rest of the codebase, we use remove() for this action. Let's keep up the consistency.

_finish() {
this._active = false;

_unbind() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's guard against the race condition/double invocation that could occur when the user removes the map while a handler is active.

Copy link
Contributor Author

@arindam1993 arindam1993 Feb 29, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think thats possible, infact the changes this PR would prevent that from happening.
Scenario one:
If a handler callback is executing, map.remove() can't be called, because well, JS is single threaded.
Scenario two:
And if map.remove() is called while a handler is still active i.e the user has the mouse held down, the callback gets unbound, so it would never invoke once the user eventually say, does a mouseup. Previous to this it would actually invoke the mouseup.

Copy link
Member

@kkaefer kkaefer Mar 2, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a handler callback is executing, map.remove() can't be called, because well, JS is single threaded.

You can call map.remove() from the callback ;)

Copy link
Contributor Author

@arindam1993 arindam1993 Mar 3, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea.. but why would we ever do that?
( Famous last words)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might not be intentional, e.g. an application could transition away from a map view (and calling map.remove()) while the user is still interacting with it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But that would be Scenario 2, which this fixes? map.remove() would still not be synchronously called in our callback, because thats our code and not user code?
That transition away would run in a different run-loop tick, so any of the enteraction callbacks would have been fully executed.

Copy link
Member

@mourner mourner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 small nit-question — if we have remove that's always an alias to _unbind, should we just rename _unbind to remove for less code?

@mourner
Copy link
Member

mourner commented Mar 5, 2020

We should probably wait until #9365 lands for an easier time reconciling the code.

@arindam1993
Copy link
Contributor Author

Sticking the DO NOT MERGE label until #9365 is merged.

@karimnaaji karimnaaji added this to the release-d milestone Mar 11, 2020
@karimnaaji karimnaaji modified the milestones: release-d, release-e Apr 6, 2020
@arindam1993
Copy link
Contributor Author

Closing since #9508 addresses thise.

@arindam1993 arindam1993 closed this Apr 8, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants