I am trying to implement some caching in my application and i want to use the default memory cache in C# (this requirement can be changed if this it wont work). My problem is that don't want to exceed the maximum amount of physical memory i have on the machine, but as i understand i can't add such a constraint to the default memory cache.
In general the policy is:
My cache can contain many different objects and they range from 10mb to 2-3gb, so i can't really get the trim
function to work.
Are there any suggestions on how to implement a LRU cache monitoring the ram usage? And hoppefully it can be done using the caches in .net?
Edit
I've added a simple example where the MemoryCache is limited to 100Mb and 20% of the physical memory, but that does not change anything. My memory is filled with no removal of cache entries. Note that the polling interval is changed to evert 5 second.
class Item
{
private List<Guid> data;
public Item(int capacity)
{
this.data = new List<Guid>(capacity);
for (var i = 0; i < capacity; i++)
data.Add(Guid.NewGuid());
}
}
class Program
{
static void Main(string[] args)
{
var cache = new MemoryCache(
"MyCache",
new NameValueCollection
{
{ "CacheMemoryLimitMegabytes", "100" },
{ "PhysicalMemoryLimitPercentage", "20" },
{ "PollingInterval", "00:00:05" }
});
for (var i = 0; i < 10000; i++)
{
var key = String.Format("key{0}", i);
Console.WriteLine("Add item: {0}", key);
cache.Set(key, new Item(1000000), new CacheItemPolicy() { UpdateCallback = UpdateHandler } );
}
Console.WriteLine("\nDone");
Console.ReadKey();
}
public static void UpdateHandler(CacheEntryUpdateArguments args)
{
Console.WriteLine("Remove: {0}, Reason: {1}", args.Key, args.RemovedReason.ToString());
}
}
Looks like the System.Runtime.Caching.MemoryCache class would fit this bill nicely. You set caching policy on a per-item basis, so if you add an item with a cache policy of SlidingExpiration with a TimeSpan of 10min, you should get the behavior you are looking for.
This is a .Net v4 class only, so it doesn't exist on earlier runtime versions. If you are in a web context, the ASP.Net cache behaves similarly, but will probably not let you manage system information.
You can set limits on cache size when you create it so that it does not exceed a certain memory footprint:
var myCache = new MemoryCache(
"MyCache",
new NameValueCollection { { "PhysicalMemoryLimit", "50" }} // set max mem pct
);
This should prevent any paging to disk, at least within your application. If there are outside memory pressures or the system is overly aggressive about paging memory to disk, your cache may still be paged out, but not due to overuse within your application. To my knowledge there is no way to reserve the memory pages in C#.