Clean up object pools and improve PooledHashSet<T>#12406
Merged
DustinCampbell merged 16 commits intodotnet:mainfrom Oct 31, 2025
Merged
Clean up object pools and improve PooledHashSet<T>#12406DustinCampbell merged 16 commits intodotnet:mainfrom
DustinCampbell merged 16 commits intodotnet:mainfrom
Conversation
Convert the various pool classes, such as ListPool<T>, from static to instance classes.
Introduce a SpecializedPools static class that contains the special pools for ReferenceEqualityComparer<T> and string hash sets, and string dictionaries.
Introduce CustomObjectPool<T> base type for custom pools, such as ListPool<T>. Provides a PooledObjectPolicy abstract class that implements IPooledObjectPolicy<T>.
This is based on Roslyn's Optional<T>, which is similar to Nullable<T> except that it can hold reference types and does not throw when `Value` is accessed and `HasValue` is false. It is particular useful for long lists of optional parameters. Note: This type is public because Razor was currently using Roslyn's Optional<T> in a couple of public places, and those are now using Razor's Optional<T>.
Now that there's a parameter for setting the maximum object size of a ListPool<T>, AbstractRazorSemanticTokensInfoService no longer needs a custom Policy object.
Introduce an IPoolableObject interface that allows a pooled object to be reset before being returned to a pool. Also, add DefaultPool.Create(...) overloads for constructing pools for IPooledObjects.
By making each of the ClassifiedSpanVisitor types implement IPoolableObject their custom Policy objects can be removed.
By making JsonDataReader and JsonDataWriter implement IPoolableObject their custom Policy objects can be removed.
Allow all TagHelperObjectBuilder<T> subtypes to remove their custom policy objects.
Allows the custom Policy type to be removed from DefaultRazorTagHelperContextDiscoveryPhase.
This change reworks PooledHashSet<T> and adds two features: 1. It is now possible to pass an IEqualityComparer<T> or a HashSetPool<T> when constructing a PooledHashSet<T>. A HashSetPool<T> will be chosen based on the IEqualityComparer<T>, or a new HashSet<T> will be created if a default pool doesn't exist. 2. A HashSet<T> won't be acquired from the pool (or created) until the set would contain at least two items.
davidwengier
approved these changes
Oct 28, 2025
ToddGrun
reviewed
Oct 29, 2025
src/Compiler/Microsoft.CodeAnalysis.Razor.Compiler/src/Language/Legacy/ParserContext.cs
Show resolved
Hide resolved
ToddGrun
reviewed
Oct 29, 2025
...mpiler/Microsoft.CodeAnalysis.Razor.Compiler/src/CSharp/DefaultTagHelperDescriptorFactory.cs
Outdated
Show resolved
Hide resolved
ToddGrun
reviewed
Oct 29, 2025
...deAnalysis.Razor.Workspaces/Serialization/MessagePack/Formatters/SerializerCachingOptions.cs
Show resolved
Hide resolved
ToddGrun
reviewed
Oct 29, 2025
src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared/PooledObjects/PooledHashSet`1.cs
Show resolved
Hide resolved
ToddGrun
reviewed
Oct 29, 2025
src/Shared/Microsoft.AspNetCore.Razor.Utilities.Shared/PooledObjects/PooledHashSet`1.cs
Show resolved
Hide resolved
This was referenced Oct 31, 2025
This was referenced Nov 3, 2025
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.
This represents some clean-up and a small performance improvement that I've intended to do for a long while. In fact, it's been sitting on my machine across a handful of branches for months. So, I decided to bring it together and submit a PR.
Key Changes:
ArrayBuilderPool<T>rather than anObjectPool<ImmutableArray<T>.Builder>.SpecializedPoolsstatic class that pulls togetherStringHashSetPool,StringDictionaryPool<TValue>, andReferenceEqualityHashSetPool<T>.MaximumObjectSizeas a knob when creating new custom pools to avoid always having to create a newIPooledObjectPolicy<T>implementation.IPoolableObjectinterface and way to create pools ofIPoolableObjects.PooledHashSet<T>to avoid acquiring aHashSet<T>from a pool until there are at least two items.CI Build: https://dev.azure.com/dnceng/internal/_build/results?buildId=2826683&view=results
Test Insertion: https://dev.azure.com/devdiv/DevDiv/_git/VS/pullrequest/684259
Toolset Run: https://dev.azure.com/dnceng/internal/_build/results?buildId=2826684&view=results