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 memory leak in ProjectRootElement.Reload #6457

Merged
merged 2 commits into from
May 24, 2021

Conversation

ladipro
Copy link
Member

@ladipro ladipro commented May 14, 2021

Fixes #6456

Context

Calling Xml.Reload on a Microsoft.Build.Evaluation.Project leaks memory because the old XmlDocument is not removed from the ProjectStringCache.

Changes Made

ClearAnyCachedStrings is now called on the document that's not retained by ProjectRootElement. This would normally be the old document being replaced by Reload.

Testing

Existing unit tests and manually verified using the repro snippet in #6456.

Notes

Targeting VS16.11 with this change as we've seen multiple feedback tickets related to this. In pathological scenarios the leak really OOMs the Visual Studio process.

Going forward we should see if we can eliminate the error-prone cache altogether (#5444).

@ladipro
Copy link
Member Author

ladipro commented May 14, 2021

I'll add a targeted regression test.

Copy link
Member

@Forgind Forgind left a comment

Choose a reason for hiding this comment

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

LGTM!


/// <summary>
/// Returns the number of documents retained by the project string cache.
/// Peeks at it via reflection since internals are not visible to these tests.
Copy link
Member

Choose a reason for hiding this comment

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

Is there any reason internals aren't visible to these tests? That seems like something we'd want for other tests later, too.

Copy link
Member Author

Choose a reason for hiding this comment

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

I believe it's by design. These tests should be testing the public surface (or Object Model, as in Build.OM.UnitTests). I'm not confident that this test case belongs here. It is testing a public method but needs an internal hook to verify the expected behavior.

Copy link
Member

Choose a reason for hiding this comment

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

It sounds a little better to me to move it to Build.UnitTests, but it isn't too important.


// Test successful reload.
projectElement.Reload(false);
GetNumberOfDocumentsInProjectStringCache(projectElement).ShouldBe(originalDocumentCount);
Copy link
Member

Choose a reason for hiding this comment

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

I'm wondering if we should verify that the project is the new one the first time and the old one the second time. Not directly related to your change, though.

More related, I'd be in favor of reloading 3-4 times just in case there's something unexpected.

@Forgind Forgind added the merge-when-branch-open PRs that are approved, except that there is a problem that means we are not merging stuff right now. label May 17, 2021
@Forgind Forgind merged commit 14572cb into dotnet:vs16.11 May 24, 2021
@ladipro ladipro linked an issue Jun 4, 2021 that may be closed by this pull request
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
merge-when-branch-open PRs that are approved, except that there is a problem that means we are not merging stuff right now.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

ProjectRootElement.Reload leaks memory in ProjectStringCache
4 participants