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

SDK Resolver assemblies leak AssemblyLoadContexts #6842

Closed
rainersigwald opened this issue Sep 13, 2021 · 4 comments · Fixed by #6864
Closed

SDK Resolver assemblies leak AssemblyLoadContexts #6842

rainersigwald opened this issue Sep 13, 2021 · 4 comments · Fixed by #6864

Comments

@rainersigwald
Copy link
Member

The SDK resolver loader should cache by assembly path much like the task loader does, and evidently does not today:

Originally posted by @marcin-krystianc in #5037 (comment)

New ALC are created because SdkResolvers need to be loaded for each evaluated project.
There is a cache for them called CachingSdkResolverService (in the EvaluationContext) so they are loaded only once per each instance of that cache. If it was possible to use single EvaluationContext for the whole lifetime of our long running service that would fix the leak from ALCs, unfortunately it is not possible as it creates other memory leaks (e.g. from the EngineFileUtilities).

@marcin-krystianc
Copy link
Contributor

One possible fix would be to make the CoreClrAssemblyLoader in the SdkResolverLoader to be a static field (https://github.com/dotnet/msbuild/blob/main/src/Build/BackEnd/Components/SdkResolution/SdkResolverLoader.cs#L20). Is it what you have in mind ?

@rainersigwald
Copy link
Member Author

@marcin-krystianc Yes, I think that would do the trick. It looks like the other uses are in statics:

private static readonly CoreClrAssemblyLoader s_coreClrAssemblyLoader;

private static readonly CoreClrAssemblyLoader _loader = new CoreClrAssemblyLoader();

Are you interested in sending a PR to fix this?

@marcin-krystianc
Copy link
Contributor

Are you interested in sending a PR to fix this?

Done in #6864

@rainersigwald
Copy link
Member Author

Awesome, thank you!

AR-May pushed a commit that referenced this issue Sep 20, 2021
We want to use static for CoreClrAssemblyLoader so each unique SDK resolver assembly is loaded into memory and JITted only once.

Fixes #6842 (comment)

### Context

We use static for the `CoreClrAssemblyLoader` field so each unique SDK resolver assembly is loaded into memory and JITted only once. All subsequent load requests will return assembly from the assembly loader's cache instead of loading it again from disk. This change increases the performance of SDK resolution and at the same time avoids leaking memory due to loading the same SDK resolver assembly multiple times and never unloading it.

### Changes Made

The `CoreClrAssemblyLoader` field in the `SdkResolverLoader` class was changed from non-static to static member. The same instance of `CoreClrAssemblyLoader` will be used by all instances of `SdkResolverLoader`. It is consistent now with other uses of `CoreClrAssemblyLoader` in msbuild.

### Testing

Tested manually using repro from #5037 (comment)

### Notes

Alternative approach would be to use collectible `CoreClrAssemblyLoader` / `AssemblyLoadContext` - that would fix the leak as well but it would be less performant as it wouldn't benefit from re-using already loaded and JITed assemblies.
@AR-May AR-May added the triaged label Feb 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants