Reputation: 47
I am having some kind of strange behavior using .NET MemoryCache in an ASP.NET application. The problem is, that objects will be evicted after a view minutes and there seems to be no reason for that. The memory limits are set in the web.config:
<system.runtime.caching>
<memoryCache>
<namedCaches>
<add name="Default"
cacheMemoryLimitMegabytes="1500"
physicalMemoryLimitPercentage="18"
pollingInterval="00:02:00" />
</namedCaches>
</memoryCache>
</system.runtime.caching>
My development machine has 8 GB of ram and the w3wp.exe process is using about 0,5 GB. 2 GB are still available on the machine when the application is running (beside visual studio, webbrowsers and so on)
A RemovedCallBack method has been added to every entry to generate log entries for every removal and expecially for evictions:
private static void CachedItemRemovedCallback(CacheEntryRemovedArguments arguments)
{
LogCurrentCacheDelta(arguments.CacheItem, true);
if (arguments.RemovedReason == CacheEntryRemovedReason.Evicted)
{
Sitecore.Diagnostics.Log.Warn(
string.Format(
"Cache Item Evicted (cacheMemoryLimitMegabytes: {0}) - Key: {1}, Value: {2}",
FlightServiceCache.CacheMemoryLimit,
arguments.CacheItem.Key,
arguments.CacheItem.Value),
FlightServiceCache);
}
}
A counter for calculating the size currently used has also been implemented. I am using a binary serialization to estimate the size of the objects in memory. At the moment, the first eviction occured, about 120 objects were in the cache and the memory used was about 6 magabytes. For my understanding, this is in no way a reason for evicting entries from cache. But it happens again and again and after to days of investigation, I am still not sure why this happens.
I also took a look at the internal implementation of the trim() function in the .NET framework source code used when objects are beeing evicted. The calculation made therefore is not easy to understand, maybe someone knows how it works and can point this out for me.
It would be great if anyone could shade some light on that.
Thank you very much in advance and sorry for the really long post ;)
(btw. this is my first post so any suggestions about how to improve my questions are highly appreciated)
Upvotes: 2
Views: 2019
Reputation: 351
Had the same exact problem. Even if I set the CacheMemoryLimit to big enough value (let's say 1GB) and the PhysicalMemoryLimit to 10% (which in my case with 32GB of physical installed memory comes to 3.2 GB), still many of my cache entries would be evicted to free cache memory. Note that I was caching 1MB items and 10 of those, so altogether 10 MB, whereas, I supposed to have at least the minimum of the two limitations mentioned above, which is 1GB.
Yes, @VMAtm, was correct in his comment above that one should use bigger %, and I tested with 10% it evicted, 50% it didn't, and with the divide and conquer method I proved that with my setup then at around 45% it no longer evicts. But note, that depending on the overall installed memory size the behaviour might be different for the % values I used for testing.
So for me the point was not to trust the PhysicalMemoryLimit % and not to set it, rather, use the CacheMemoryLimit config property only. And if you still need to prove an option with the PhysicalMemoryLimit % then instead of using the system.runtime.caching configuration settings, rather, introduce your own settings, read them, get the actual physical installed memory size, use your percentage setting and then calculate the minimum of the two: physical memory limit (now in bytes) and cache memory limit (in bytes from your own setting). Having that you can then create MemoryCache and pass only the cacheMemoryLimitMegabytes config through NameValueCollection to its constructor, and the value for the cacheMemoryLimitMegabytes config property will be that minimum of two calculated above.
BTW to get the total physical installed memory size one can use:
[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool GetPhysicallyInstalledSystemMemory(out long totalMemoryInKilobytes);
Upvotes: 1