Access cache stats with MemoryCacheStatistics

Using MemoryCacheStatistics to better understand MemoryCache usage in an application

Home DailyDrop

Daily Knowledge Drop

Coming with .NET 7, the MemoryCacheStatistics class, accessed through IMemoryCache.GetCurrentStatistics can provider useful statistics regarding the state of the memory cache. These include:

  • how many items are currently in the cache
  • the current estimate size of the cache
  • the number of times the cache has been queried for a value, and the value was not present (misses)
  • the number of times the cache has been queried for a value, and the value was present (hits)

These stats can be leveraged to better understand how/if the cache mechanism is correctly configured and being used optimally.


Cache configuration

The first step is to register the require cache implementation instances with the dependency injection container. This is done using the AddMemoryCache extension method:

builder.Services
    .AddMemoryCache(memCacheOptions => 
        { 
            memCacheOptions.TrackStatistics = true; 
            memCacheOptions.SizeLimit = 1024; 
        });
  • For stats to be tracked, the MemoryCacheOptions.TrackStatistics value (memCacheOptions.TrackStatistics in the above example) needs to be set to true
  • For the EstimateSize property of the statistics to be tracked, the cache needs to have a SizeLimit specified. The SizeLimit does not represent memory size, but number of units - in the above example, the limit has been set to 1024 units, and when items are added to the cache one byte will be treated as a unit (this is not a required, its up to the developer to decide how many "units" each item added to the cache is worth)

Cache usage

Set values

Now that the cache is configured, the next step is to start using it to store values. A simple getnumber endpoint is defined, which will return the number passed in:

  • if the number does not exist in the cache, it will be added to the cache and returned
  • if the number already exists in the cache, it will be returned from the cache
// get the number from the route
// get the IMemoryCache from the DI container
app.MapGet("/getnumber/{number}", ([FromRoute]int number, 
    [FromServices] IMemoryCache cache) =>
{
    // first check the cache to see if the number
    // exists there
    if(cache.TryGetValue(number, out var value))
    {
        return $"'{value}' retrieved from cache";
    }

    // if it didn't exist, add it to the cache
    cache.Set(number, number, new MemoryCacheEntryOptions { Size = sizeof(int)});

    // return
    return $"'{number}' added to cache";
});

Invoking the endpoint with a number for the first time /getnumber/1, will result in:

'1' added to cache

While invoking subsequent times with the same number will result in:

'1' retrieved from cache

The cache has been configured and the endpoint called a number of times, with unique and duplicate numbers, so next let's have a look at the stats.


Get statistics

To get a snapshot of the IMemoryCache statistics, the GetCurrentStatistics method is used:

app.MapGet("/getstats", ([FromServices] IMemoryCache cache) =>
{
    return cache.GetCurrentStatistics();
});

A sample return snapshot:

{
    "currentEntryCount":6,
    "currentEstimatedSize":24,
    "totalMisses":6,
    "totalHits":2
}

In this example:

  • 6 items have been added to the cache
  • the 6 items take up 24 of the available 1024 units available (6 x 4 bytes)
  • the cache has been checked and did not contain the queried value 6 times
  • the cache has been checked and did contain the queried value twice

Notes

This information is very valuable and can be leveraged to confirm if the cache configured for an application is successfully being used - over time, one would want to see a high number of hits and relatively low number of misses. This information can be used to determine if the cache strategy needs to be modified (cache based on a different key) or maybe increase or decrease the cache size.


References

IMemoryCache.GetCurrentStatistics Method

Daily Drop 183: 17-10-2022

At the start of 2022 I set myself the goal of learning one new coding related piece of knowledge a day.
It could be anything - some.NET / C# functionality I wasn't aware of, a design practice, a cool new coding technique, or just something I find interesting. It could be something I knew at one point but had forgotten, or something completely new, which I may or may never actually use.

The Daily Drop is a record of these pieces of knowledge - writing about and summarizing them helps re-enforce the information for myself, as well as potentially helps others learn something new as well.
c# .net cache memorycache statistics