High Contention in MemoryCache _cacheSize Updates Causing Performance Degradation
Nobody has claimed this yet.
Assessment
- Difficulty
- 5/5
- Estimated time
- Over a week
- Newbie friendliness
- 35/100
- Issue type
- Bug
- Clarity
- Mostly clear
- Activity status
- Stale
- Tech stack
- csharp
- Domain
- backend, performance
Research direction
Start by locating MemoryCache and the UpdateCacheSizeExceedsCapacity method, then review how _cacheSize is updated during concurrent cache writes. Reproduce the provided Parallel.For example on .NET 9 and measure CPU usage and throughput under contention. Done means a validated approach reduces contention without changing cache capacity behavior.
Written by the indexing model from the issue text.
Description
Description
The current implementation of MemoryCache updates _cacheSize using Interlocked.CompareExchange in a retry loop (up to 100 times). This creates high contention when multiple threads attempt to modify _cacheSize, leading to increased CPU usage and reduced throughput under high concurrency.
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options;
var cache = new MemoryCache(Options.Create(new MemoryCacheOptions { SizeLimit = 1000 }));
Parallel.For(0, 100, i =>
{
cache.Set(i, i, new MemoryCacheEntryOptions { Size = 10 });
});
Console.WriteLine($"Cache Count: {cache.Count}");
Issue: When running with a high number of concurrent threads, CPU usage spikes and cache performance degrades due to frequent retries in UpdateCacheSizeExceedsCapacity.
Configuration
.NET Version: .NET 9
OS: Windows 11
Architecture: x64
Machine Specs: 16-core CPU, 16GB RAM
Regression?
Not a regression but a long-standing inefficiency in MemoryCache.
Data
Analysis
Problem:
-
Interlocked.CompareExchange retried up to 100 times under contention.
-
Causes CPU spikes when multiple threads modify _cacheSize.
-
Locks too frequently, slowing down high-throughput applications.
Proposed Fix:
✅ Use ConcurrentQueue<long> for batch updates instead of per-entry updates.
✅ Process updates asynchronously in a background task, reducing lock contention.
✅ Minimize atomic operations on _cacheSize, improving cache scalability.
- Dominant language
- C#
- Stars
- 18.3k
- Forks
- 5.6k
- PR merge metrics
- PR metrics pending
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from dotnet/runtime
-
agentic-workflows untriaged
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
-
area-System.Reflection blocking-clean-ci-optional Known Build Error os-mac-os-x untriaged
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
-
area-CodeGen-coreclr untriaged
Difficulty 1/5 Under an hour Newbie friendliness 92/100
-
agentic-workflows untriaged
Difficulty 1/5 Under an hour Newbie friendliness 78/100
-
area-VM-meta-mono untriaged
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 86/100
-
:watch: Not Triaged 11.0 fundamentals/subsvc
Difficulty 2/5 1-3 hours Newbie friendliness 92/100
dotnet/AspNetCore.Docs#37699 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
SubtitleEdit/subtitleedit#15108 · 1 comment ·
-
area/docs-content Bug pulumi/docs
Difficulty 1/5 1-3 hours Newbie friendliness 94/100
-
Create parent directories only after the containment check in InstallHelper.TryExtractToDirectory Open
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
PowerShell/PSResourceGet#2056 ·