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

fix(grid): plug a memory leak from the render process #3721

Merged
merged 1 commit into from Oct 18, 2023
Merged

Conversation

Westbrook
Copy link
Collaborator

Description

Rendering a lit-html template with render() without caching it's root part means that you can't inform it when the template is connected to the DOM or not. This connection state is required to ensure clean up can happen to any of the template directives that might be leveraged therein. If the Virtualize template directive does not get disconnected it can leak references to the items it had previously rendered to the DOM.

Cache a reference to the "grid part" in the Grid element for the DOM that would otherwise have been rendered to the render root and managed directly by LitElement. Manage the connected state of this cached part.

Related issue(s)

How has this been tested?

Types of changes

  • Bug fix (non-breaking change which fixes an issue)

Checklist

  • I have signed the Adobe Open Source CLA.
  • My code follows the code style of this project.
  • If my change required a change to the documentation, I have updated the documentation in this pull request.
  • I have read the CONTRIBUTING document.
  • I have added tests to cover my changes.
  • All new and existing tests passed.

@Westbrook Westbrook requested a review from jblas October 13, 2023 23:31
@github-actions
Copy link

github-actions bot commented Oct 13, 2023

Tachometer results

Chrome

grid permalink

Version Bytes Avg Time vs remote vs branch
npm latest 460 kB 61.95ms - 63.91ms - unsure 🔍
-0% - +4%
-0.01ms - +2.64ms
branch 428 kB 60.72ms - 62.50ms unsure 🔍
-4% - -0%
-2.64ms - +0.01ms
-
Firefox

grid permalink

Version Bytes Avg Time vs remote vs branch
npm latest 460 kB 106.92ms - 116.24ms - unsure 🔍
-5% - +6%
-5.83ms - +7.03ms
branch 428 kB 106.55ms - 115.41ms unsure 🔍
-6% - +5%
-7.03ms - +5.83ms
-

expect(
afterMB - beforeMB,
`before: ${beforeMB}, after: ${afterMB}`
).to.be.lt(0);
Copy link
Contributor

Choose a reason for hiding this comment

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

You can also potentially use a WeakRef to the Grid element and wait a certain amount of time/ trigger garbage collection and expect the deref() to return undefined. This might be more deterministic than measuring heap memory.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Opted for the more reliable, but slightly more cumbersome to surface, [performance.measureUserAgentSpecificMemory()](https://chromestatus.com/feature/5685965186138112) for now. Showing even more positive results from this change when measuring with this API.

I know the team has been looking at tooling with WeakMaps, I wonder how you're actually holding things in that way as it feels like the need for the key would inherently keep a reference and prevent the memory from being released. You wouldn't happen to have any examples to share?

Copy link
Contributor

Choose a reason for hiding this comment

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

We're mainly using WeakRef different from WeakMap. The basic idea is to construct a new WeakRef passing in the DOM node you're interested in tracking, trigger garbage collection, and then test whether or not calling WeakRef.deref() on your reference returns undefined. If so, you can assume the node was garbage collected. It not fool-proof but it has been working quite nicely for us.

Here is the original dom inspection snippets that Kin created: https://git.corp.adobe.com/jblas/debug-utils/tree/main/snippets#object-watcher

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is cool, I didn't realize that WeakRef was different than WeakMap! Definitely a useful pattern for the future, particularly as a comparison for test speed for tightening the feedback cycle.

Digging into measureUserAgentSpecificMemory() will also give us some other useful tidbits later on, for an expanded perf testing suite, so getting started now seems useful.

najikahalsema
najikahalsema previously approved these changes Oct 18, 2023
Copy link
Collaborator

@najikahalsema najikahalsema left a comment

Choose a reason for hiding this comment

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

LGTM! Never used MSEdge until today 😅

@@ -135,5 +143,5 @@ export default {
},
],
group: 'unit',
browsers: [chromium, firefox, webkit],
browsers: [chromiumWithMemoryTooling, firefox, webkit],
Copy link
Collaborator

Choose a reason for hiding this comment

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

is it safe to run this "flag-customized" version of chromium for all tests? or should you create a group config using it that focuses only on the grid memory tests?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

In that the tests run and pass, I have no other path to judge "safety" here.

This is a great point though, and segmenting these out, for safety/performance/understandability/etc, as part of #3722 would make a lot of sense!

@Westbrook Westbrook merged commit 4414bd9 into main Oct 18, 2023
45 of 47 checks passed
@Westbrook Westbrook deleted the grid-leak branch October 18, 2023 21:23
@Rajdeepc Rajdeepc changed the title fix(grid): plug a mememory leak from the render process fix(grid): plug a memory leak from the render process Mar 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
4 participants