Sto lavorando con la classe .NET 4.0 MemoryCache in un'applicazione e sto cercando di limitare la dimensione massima della cache, ma nei miei test non sembra che la cache stia effettivamente rispettando i limiti.
Sto usando le impostazioni che, secondo MSDN , dovrebbero limitare la dimensione della cache:
- CacheMemoryLimitMegabytes : la dimensione massima della memoria, in megabyte, che può raggiungere un'istanza di un oggetto. "
- PhysicalMemoryLimitPercentage : "La percentuale di memoria fisica che la cache può utilizzare, espressa come valore intero compreso tra 1 e 100. Il valore predefinito è zero, che indica che leistanze di MemoryCache gestiscono la propria memoria 1 in base alla quantità di memoria installata sul computer." 1. Questo non è del tutto corretto: qualsiasi valore inferiore a 4 viene ignorato e sostituito con 4.
Capisco che questi valori sono approssimativi e non limiti rigidi poiché il thread che elimina la cache viene attivato ogni x secondi e dipende anche dall'intervallo di polling e da altre variabili non documentate. Tuttavia, anche tenendo conto di queste variazioni, vedo dimensioni della cache estremamente incoerenti quando il primo elemento viene rimosso dalla cache dopo aver impostato CacheMemoryLimitMegabytes e PhysicalMemoryLimitPercentage insieme o singolarmente in un'app di test. Per essere sicuro ho eseguito ogni test 10 volte e ho calcolato la cifra media.
Questi sono i risultati del test del codice di esempio riportato di seguito su un PC Windows 7 a 32 bit con 3 GB di RAM. La dimensione della cache viene presa dopo la prima chiamata a CacheItemRemoved () in ogni test. (Sono consapevole che la dimensione effettiva della cache sarà maggiore di questa)
MemLimitMB MemLimitPct AVG Cache MB on first expiry
1 NA 84
2 NA 84
3 NA 84
6 NA 84
NA 1 84
NA 4 84
NA 10 84
10 20 81
10 30 81
10 39 82
10 40 79
10 49 146
10 50 152
10 60 212
10 70 332
10 80 429
10 100 535
100 39 81
500 39 79
900 39 83
1900 39 84
900 41 81
900 46 84
900 49 1.8 GB approx. in task manager no mem errros
200 49 156
100 49 153
2000 60 214
5 60 78
6 60 76
7 100 82
10 100 541
Ecco l'applicazione di prova:
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Runtime.Caching;
using System.Text;
namespace FinalCacheTest
{
internal class Cache
{
private Object Statlock = new object();
private int ItemCount;
private long size;
private MemoryCache MemCache;
private CacheItemPolicy CIPOL = new CacheItemPolicy();
public Cache(long CacheSize)
{
CIPOL.RemovedCallback = new CacheEntryRemovedCallback(CacheItemRemoved);
NameValueCollection CacheSettings = new NameValueCollection(3);
CacheSettings.Add("CacheMemoryLimitMegabytes", Convert.ToString(CacheSize));
CacheSettings.Add("physicalMemoryLimitPercentage", Convert.ToString(49)); //set % here
CacheSettings.Add("pollingInterval", Convert.ToString("00:00:10"));
MemCache = new MemoryCache("TestCache", CacheSettings);
}
public void AddItem(string Name, string Value)
{
CacheItem CI = new CacheItem(Name, Value);
MemCache.Add(CI, CIPOL);
lock (Statlock)
{
ItemCount++;
size = size + (Name.Length + Value.Length * 2);
}
}
public void CacheItemRemoved(CacheEntryRemovedArguments Args)
{
Console.WriteLine("Cache contains {0} items. Size is {1} bytes", ItemCount, size);
lock (Statlock)
{
ItemCount--;
size = size - 108;
}
Console.ReadKey();
}
}
}
namespace FinalCacheTest
{
internal class Program
{
private static void Main(string[] args)
{
int MaxAdds = 5000000;
Cache MyCache = new Cache(1); // set CacheMemoryLimitMegabytes
for (int i = 0; i < MaxAdds; i++)
{
MyCache.AddItem(Guid.NewGuid().ToString(), Guid.NewGuid().ToString());
}
Console.WriteLine("Finished Adding Items to Cache");
}
}
}
Perché MemoryCache non obbedisce ai limiti di memoria configurati?