Skip to content

Conversation

majocha
Copy link
Contributor

@majocha majocha commented Aug 30, 2025

The type subsumption cache was causing problems with the legacy 32 bit test projects.

This was swept under a rug for a few months, using a cache capacity override in tests.
In the course of #18872 I had to revisit this because it showed up again.

I captured a memory snapshot during tests to see what's going on.
Turns out the TType objects used as cache keys were the problem.
They can reference a lot of additional lazy initialized data, including ginormous circular references. Now when we put them as cache keys, that can extend their life well beyond their natural lifespan. This was not a big problem memory wise in normal use, but somehow 32 bit tests couldn't handle it and had hard time GCing this.
For example If I weakly attached the cache to TcGlobals. This was correctly GC'd in other test projects but never collected in VS tests.

Anyway, the fix is to use a synthetic key, created as a slim structural representation of TType in such a way as to guarantee equality soundness.

I checked (by capturing telemetry from the test run) that the cache still works, hit ratio is still good and evictions happen ok.

Copy link
Contributor

github-actions bot commented Aug 30, 2025

⚠️ Release notes required, but author opted out

Warning

Author opted out of release notes, check is disabled for this pull request.
cc @dotnet/fsharp-team-msft

@T-Gro T-Gro added the NO_RELEASE_NOTES Label for pull requests which signals, that user opted-out of providing release notes label Sep 2, 2025
/// Usage:
/// let getValueFor = WeakMap.getOrCreate (fun key -> expensiveInit key)
/// let v = getValueFor someKey
let getOrCreate valueFactory =
Copy link
Member

Choose a reason for hiding this comment

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

Why is it called getOrCreate ? Doesn't it always create a new table?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I hope not. It calls ConditionalWeakTable.GetValue factory overload, so it should get the existing attached property or create a new one.

@majocha
Copy link
Contributor Author

majocha commented Sep 2, 2025

Just to have this data somewhere: as of current commit hit ratio measured over ComponentTests net10 is 75.8%, no eviction fails.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
NO_RELEASE_NOTES Label for pull requests which signals, that user opted-out of providing release notes
Projects
Status: New
Development

Successfully merging this pull request may close these issues.

2 participants