Home / Forums / High-Performance Thread-Safe Caching with MemoryCache & LRU Eviction

UnreliableCode Community

Developer Research, Reverse Engineering & Coding Community

Source

High-Performance Thread-Safe Caching with MemoryCache & LRU Eviction

DevDan
.NET Core & Cloud
MEMBER
Rep: 324
Join Date: Feb 2021
Posts: 16
Thanks: 65
1y ago · Jan 15, 2025 11:20 AM
#1
Building an in-memory cache using
CODE
Microsoft.Extensions.Caching.Memory
with size limits, sliding expiration, and automatic compaction:

CSHARP
using Microsoft.Extensions.Caching.Memory;

public class GameAssetCache
{
    private readonly IMemoryCache _cache = new MemoryCache(new MemoryCacheOptions
    {
        SizeLimit = 1024, // Max 1,024 cached items
        CompactionPercentage = 0.20 // Evict 20% least-recently-used on full limit
    });

    public async Task<byte[]> GetOrLoadAssetAsync(string assetName)
    {
        return await _cache.GetOrCreateAsync(assetName, async entry =>
        {
            entry.SetSize(1);
            entry.SetSlidingExpiration(TimeSpan.FromMinutes(10));
            entry.SetAbsoluteExpiration(TimeSpan.FromHours(1));

            return await LoadAssetFromDiskAsync(assetName);
        })!;
    }
}


Why this is better than a raw ConcurrentDictionary:
- Automatically evicts items when memory size limit is reached.
- Thread-safe lazy loading with
CODE
GetOrCreateAsync
prevents duplicate disk loads when multiple requests ask for the same item simultaneously!
DevDan · .NET Core & Cloud
Writing clean C# code and microservices since .NET Core 2.1....
The following users thanked DevDan for this post:
CSharpNinja
Senior .NET Developer
VIP
Rep: 329
Join Date: Jan 2020
Posts: 16
Thanks: 75
1y ago · Jan 15, 2025 3:32 PM
#2
The automatic compaction percentage is essential for keeping memory bounded in microservices. A raw dictionary without eviction will inevitably OOM (Out-Of-Memory) over weeks of uptime.
CSharpNinja · Senior .NET Developer
C# enthusiast, building distributed backend services and hig...
AsyncMaster
Concurrency Geek
MEMBER
Rep: 72
Join Date: Jul 2020
Posts: 13
Thanks: 83
1y ago · Jan 15, 2025 6:32 PM
#3
CODE
PostEvictionCallbacks
are also useful if you need to dispose native graphics handles (like DirectX textures) when an asset is evicted from the cache!
AsyncMaster · Concurrency Geek
Task Parallel Library (TPL), async/await internals, and lock...