Skip to content

[release/8.0] - Port perf fixes to 8.0#556

Open
joeloff wants to merge 3 commits intodotnet:release/8.0from
joeloff:545on8
Open

[release/8.0] - Port perf fixes to 8.0#556
joeloff wants to merge 3 commits intodotnet:release/8.0from
joeloff:545on8

Conversation

@joeloff
Copy link
Copy Markdown
Member

@joeloff joeloff commented May 4, 2026

Porting changes from #545 to 8.0. To flow to Visual Studio, the updated assemblies need to go into the SDK template locator and MSBuild resolver.

Customer Impact

  • Found internally

Reduces allocations in Visual Studio when process releases JSON data, improving performance. The library is used by both the SDK resolver and template locator. Additionally, the New Project Dialog also uses it to provide information related to EOL versions of .NET.

Regression

  • Yes
  • No

Testing

Manual testing.

Risk

Low

davkean added 3 commits May 4, 2026 09:39
Replace TextReader.ReadToEndAsync() + JsonDocument.Parse(string) with
JsonDocument.ParseAsync(Stream) in both ProductCollection.GetAsync and
Product.GetReleasesAsync. This eliminates the intermediate StringBuilder
growth (~15 MB), the LOH string materialization from ToString (~13 MB),
and the re-encoding back to UTF-8 for JsonDocument (~6 MB) per file
parsed -- roughly 34 MB of transient allocations for a typical
releases.json file.
ReleaseFile.GetHashCode() called Uri.GetHashCode() which forces
EnsureUriInfo/CreateUriInfo (allocating UriInfo), GetComponentsHelper/
EnsureHostString (allocating host String), and MoreInfo objects. These
lazy-parse allocations accounted for ~3.7 MB across 34 allocation tick
samples during template loading.

Use Address.OriginalString.GetHashCode() instead, which returns the
already-stored string without triggering any URI parsing. The Equals
method still uses Uri.operator== for correctness, but GetHashCode no
longer forces the expensive parse path.
Store the URL as a string during JSON deserialization and lazily construct
the Uri only when Address is accessed (for DownloadAsync or FileName).
During template loading, ReleaseFile objects are created for every file
in every release, but the Uri is never accessed -- only Hash, Name, and
Rid are used for the Distinct() deduplication. The eager Uri construction
allocated Char[] (CheckForUnicode), String (ParseScheme, host parsing),
UriInfo, and MoreInfo objects per file -- visible across all three
component types in the allocation trace.

Also switch Equals to use string comparison on the URL instead of
Uri.operator== to avoid forcing Uri construction during equality checks.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants