Keep strong reference to virtual project's ProjectRootElement to prevent GC#53807
Merged
jjonescz merged 2 commits intodotnet:release/10.0.3xxfrom Apr 14, 2026
Merged
Conversation
…ent GC When dotnet run --file builds a virtual .csproj in memory, the ProjectRootElement is only held alive by MSBuild's ProjectRootElementCache which may demote it to a weak reference when many SDK import files fill the cache (e.g., in large repos with Directory.Packages.props). If GC collects the weakly referenced element, nested <MSBuild> tasks during NuGet restore that re-evaluate the project with different properties fail to find it in the cache, try to load from disk, and throw MSB4025 because the virtual file does not exist. Fix: Store the ProjectRootElement in a field on VirtualProjectBuilder so it stays alive for the duration of the build. Fixes dotnet#52714 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add VirtualProject_SurvivesGCDuringRestore test that forces GC of the virtual project's ProjectRootElement during NuGet restore by: - Setting MSBUILDPROJECTROOTELEMENTCACHESIZE=1 to ensure immediate eviction - Using an inline task in Directory.Build.targets to call GC.Collect() before the nested <MSBuild> task in _FilterRestoreGraphProjectInputItems Without the strong reference fix, this test reliably reproduces MSB4025. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Fixes an intermittent dotnet run --file failure where MSBuild can lose the in-memory virtual project (ProjectRootElement) if it is only weakly referenced in the MSBuild cache during restore, leading to MSB4025 when MSBuild attempts to reload the non-existent .csproj from disk.
Changes:
- Keep a strong reference to the virtual project’s
ProjectRootElementonVirtualProjectBuilderfor the duration of the build. - Add a regression test that forces MSBuild’s strong PRE cache eviction and triggers GC during NuGet restore.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| test/dotnet.Tests/CommandTests/Run/RunFileTests.cs | Adds a regression test covering GC + MSBuild PRE cache eviction during restore for file-based dotnet run. |
| src/Microsoft.DotNet.ProjectTools/VirtualProjectBuilder.cs | Stores the created ProjectRootElement in an instance field to prevent GC when MSBuild demotes cache entries to weak references. |
RikkiGibson
approved these changes
Apr 10, 2026
MiYanni
approved these changes
Apr 13, 2026
333fred
approved these changes
Apr 13, 2026
Member
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
When
dotnet run --filebuilds a virtual.csprojin memory, theProjectRootElementis only held alive by MSBuild'sProjectRootElementCachewhich may demote it to a weak reference when many SDK import files fill the cache (e.g., in large repos withDirectory.Packages.props). If GC collects the weakly referenced element, nested<MSBuild>tasks during NuGet restore that re-evaluate the project with different properties fail to find it in the cache, try to load from disk, and throw MSB4025 because the virtual file does not exist.Fix: Store the
ProjectRootElementin a field onVirtualProjectBuilderso it stays alive for the duration of the build.Fixes #52714