Skip to content

Clean up object pools and improve PooledHashSet<T>#12406

Merged
DustinCampbell merged 16 commits intodotnet:mainfrom
DustinCampbell:pool-clean-up
Oct 31, 2025
Merged

Clean up object pools and improve PooledHashSet<T>#12406
DustinCampbell merged 16 commits intodotnet:mainfrom
DustinCampbell:pool-clean-up

Conversation

@DustinCampbell
Copy link
Member

@DustinCampbell DustinCampbell commented Oct 28, 2025

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:

  • The custom pool classes are now instance classes rather than static classes. So, it's not possible to create an instance of an ArrayBuilderPool<T> rather than an ObjectPool<ImmutableArray<T>.Builder>.
  • Introduce a SpecializedPools static class that pulls together StringHashSetPool, StringDictionaryPool<TValue>, and ReferenceEqualityHashSetPool<T>.
  • Add MaximumObjectSize as a knob when creating new custom pools to avoid always having to create a new IPooledObjectPolicy<T> implementation.
  • Introduce an IPoolableObject interface and way to create pools of IPoolableObjects.
  • Improve PooledHashSet<T> to avoid acquiring a HashSet<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

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.
@DustinCampbell DustinCampbell requested a review from a team as a code owner October 28, 2025 21:21
Copy link
Contributor

@ToddGrun ToddGrun left a comment

Choose a reason for hiding this comment

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

:shipit:

@DustinCampbell DustinCampbell merged commit 49b30fd into dotnet:main Oct 31, 2025
11 checks passed
@DustinCampbell DustinCampbell deleted the pool-clean-up branch October 31, 2025 19:38
@dotnet-policy-service dotnet-policy-service bot added this to the Next milestone Oct 31, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants