-
Notifications
You must be signed in to change notification settings - Fork 367
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
Fix memory leaks and failed cleanups in destroyables Mutation Observer #17687
Conversation
Do you have any documentation showing 3 is true? Everything I could find states they're cleaned up once the observation target is garbage-collected. |
I'm also not clear on what is meant by 2: using the observed nodes as keys was not a mistake. |
07fc81f
to
764a045
Compare
No real documentation, just a closed (because duplicate) issue on the whatwg github whatwg/dom#484 that then links to the issue of being able to disconnect single targets instead of all or nothing: whatwg/dom#126 There are no details or measurements available in these issues unfortunately. This prompted me to do my own testing though, and from my testing in chrome at least, MutationObserver does indeed keep a strong reference to the html element it is observing. And this with the same code base, but just the following part removed: context.observer.disconnect(); The methodology is the same as in my previous PR: opening, then closing a sheet (character sheet in this example), then running manual garbage collection, repeating a few times. |
The observed nodes will never appear in the Example HTML structure: NPC sheetConsider the following simplified HTML structure for an NPC sheet: <body>
<div class="window window-app npc">
<section class="window-content">
<form>
<tagify-tags></tagify-tags>
</form>
</section>
</div>
</body> In this example, suppose the For simplicity, let's assume this is the first and only Adding to the
|
The previous approach of just destroying every destroyable for an application whenever the content was replaced had potential issues for cases when only a subset of the DOM was being replaced, as is potentially planned for the kingdom and/or party sheet
101ecfa
to
7d772cd
Compare
I think the fix for the body observer is to simply set the keys to the application frame rather than the content-window element. |
That should work, yes. |
This should be better now, using only a single observer to watch for changes of the |
I think you can drop the |
I'm not sure about that. I currently check for the inclusion of the html node linked to the We could as of now probably live without the |
Try checking the return of the tooltipster instance's |
Your are absolutely right, don't know why I missed that. Probably only looked at properties, not functions... |
The ad-hoc tooltipster instance type can also be removed as this is already available as |
I really do like the Idea of using Mutation Observer for the otherwise errorprone task of cleanup up the
tooltipster
,Sortable
andTagify
instances. I wish I had thought of that when authoring my PR.However, I have identified some issues with the current implementation that this PR aims to address:
Tooltipster cleanup timing
Tooltipster instances normally to be destroyed before their associated DOM elements are removed. Tooltipster relies on jQuery’s .data attribute to store references to its instances, and these attributes are cleared when elements are removed via jQuery. If the destroy method is called after this happens, Tooltipster logs warnings or even throws errors.
Additionally, the instance itself is not automatically destroyed, and it retains a reference to the original HTML element. This alone isn’t enough to cause a memory leak, but Tooltipster's internal
setInterval
that closes over the tooltipster instance creates one.Handling removed nodes in MutationObserver
The
removedNodes
property in the MutationObserver callback does not include the node it was registered for (the target). While the current implementation addresses this by observing a parent element (the closest .window-content element), the mutation handler mistakenly tries to use removed nodes as keys to access destroyable items. This approach will never succeed since the observed target is not included inremovedNodes
.Memory Leaks from unmanaged MutationObservers
MutationObservers themselves can lead to memory leaks if not explicitly
disconnect()
ed. They will continue observing their target nodes even after those nodes are removed from the DOM. An explicit call to disconnect is necessary to release connected nodes and prevent memory leaks.Proposed Fixes
This PR resolves these issues by:
$(el).data('tooltipster-ns')
to access the tooltipster instance, but is unavoidable.MutationObserver
s to avoid residual references.I have verified that after these changes, no memory leaks occur in NPC sheets, item/feat sheets, and character sheets. However, IWR tooltips in the chat log still exhibit memory leaks. This is because chat messages and their tooltips are rendered before being inserted into the popped-out chat log application, complicating the setup of
MutationObserver
s. Addressing this specific issue will require a separate investigation.