Currently, the property summary for the MemoryCacheOptions.SizeLimit property is:
/// <summary>
/// Gets or sets the maximum size of the cache.
/// </summary>
It would be nice if this explicitly provided the unit of measure (bytes, kilobytes, etc.). Like this:
/// <summary>
/// Gets or sets the maximum size of the cache in kilobytes.
/// </summary>
This was deliberate. The memory cache does not measure the size of its contents, it relies on the entries to self-declare their size. The units are arbitrary so long as those sharing the cache agree.
It might be worth mentioning that, then.
@Eilon I wholeheartedly agree. For example, I intended to use the default implementation of the InMemory cache provider in a very small website to store lookup values that I don't update often. I have a set cache size in mind (in bytes), but I'm not sure how to specify this given the documentation.
How am I supposed to set the size of the entries ? Is it safe to use Marshal.SizeOf() method the get the size of entries I'm adding to cache with SetSize() method ? Like below:
//GET ORGANIZATION NAMES FROM CACHE
public async Task<List<Organization>> GetOrganizationNames()
{
string key = CacheKeys.Organizations;
if (!_cache.TryGetValue(key, out List<Organization> organizations))
{
organizations = await _db.Organization.Select( o=>new Organization() { Id=o.Id ,Name=o.Name}).ToListAsync();
var cacheEntryOptions = new MemoryCacheEntryOptions()
.SetSlidingExpiration(TimeSpan.FromMinutes(3))
.SetPriority(CacheItemPriority.High)
.AddExpirationToken(new CancellationChangeToken(OrganizationsToken.Token))
.SetSize(Marshal.SizeOf(organizations));
_cache.Set(key, organizations, cacheEntryOptions);
}
return organizations;
}
@brainoverflow98 I think it's doubtful that Marshal.SizeOf
will be of much use here unless the object is very simple. I don't think it will account for complex types that include references to other object instances, which could be of enormous sizes.
@brainoverflow98 I think it's doubtful that
Marshal.SizeOf
will be of much use here unless the object is very simple. I don't think it will account for complex types that include references to other object instances, which could be of enormous sizes.
So can I consider it as safe on an object which only has 2 string values ? And what other solutions I can use for limiting the size properly ? I'm trying to implement a good db cache system.
@brainoverflow98 - I don't think it'll work the way you want in any case where a reference type is involved, such as string
. It'll return something like 16
for an object that has 2 strings because that's the size of 2 'pointers' (1 pointer for each string). If your object type only has 2 strings, and you always know that, you can do s1.Length + s2.Length
(w/ null checks, if needed).
@Eilon Is there any way that I can track the size of complex types or better if there is any way I can controll the memory usage of MemoryCache ?
Unfortunately I don't think there's any good general-purpose way of doing this. If there was, it would likely have been built-in.
Because it's so complex and not generalizable, it's left up to each person using the cache to use the "size" logic that makes sense for them.
Here's one example where we estimate the size of a specific structure.
https://github.com/aspnet/ResponseCaching/blob/c1cb7576a0b86e32aec990c22df29c780af29ca5/src/Microsoft.AspNetCore.ResponseCaching/Internal/CacheEntry/CacheEntryHelpers%20.cs#L11-L40
Note there are no units on the cache size field. You don't need to account for every last byte, but rather you need to ensure that you use a consistent approach across the objects you cache.
@Eilon @Tratcher Thank you so much guys ! One last question, do I need to make any configurations to use clear on memory pressure option or is it going to be configured all by the program based on the OS it works?
Memory cache does not account for memory pressure, only the size limit you specify. Adding new items that exceed the limit can cause old items to to be removed, or the new items might not get added depending on priorities.
So, it's been a couple of years... and it's still not updated in the docs -- and the MSDN documentation doesn't even mention this (in fact the example code is out dated and using properties that don't exist like MemoryCache.Default
).
CacheEntry.Size doesn't even mention if it has a default value or not -- can I assume the default value is 1?
Most helpful comment
It might be worth mentioning that, then.