Я использую MemoryCache с зависимостями Sql.
Я заметил, что при использовании MemoryCache.Set () происходит утечка памяти, если элемент перезаписывается в коллекции. Рассмотрим следующий сценарий:
- Элемент с ключом = A вставляется в кеш с зависимостью от Table1
- Новый элемент с тем же ключом = a повторно вставляется с помощью .Set () с зависимостью от Table2
- Таблица 2 изменилась в базе данных.
-> Ключ элемента = a действительно был удален из кэша, но его память все еще используется в MemoryCache. Память освобождается только при изменении данных для Таблицы 1 в базе данных.
Воспроизвести код:
public partial class Form1 : Form
{
const string cs = @"Data Source=.\sqlexpress;Initial Catalog=TestDB;";
public Form1()
{
SqlDependency.Start(cs);
InitializeComponent();
}
MemoryCache memCache = new MemoryCache("test1", new NameValueCollection {
{ "pollingInterval", "00:00:03"}});
private void button2_Click(object sender, EventArgs e)
{
var dep1 = GetDep("SELECT ID FROM dbo.Table1");
var dep2 = GetDep("SELECT ID FROM dbo.Table2");
var policy = new CacheItemPolicy();
policy.SlidingExpiration = new TimeSpan(2, 0, 0);
policy.ChangeMonitors.Add(new SqlChangeMonitor(dep1));
memCache.Set("a", GetSB(), policy);
var policy2 = new CacheItemPolicy();
policy2.SlidingExpiration = new TimeSpan(2, 0, 0);
policy2.ChangeMonitors.Add(new SqlChangeMonitor(dep2));
memCache.Set("a", GetSB(), policy2);
}
private object GetSB()
{
StringBuilder sb = new StringBuilder(100000000);
for (var i = 0; i < sb.Capacity; i++)
{
sb.Append("1");
}
return sb.ToString();
}
private static SqlDependency GetDep(string sql)
{
SqlConnection con = new SqlConnection(cs);
var cmd = new SqlCommand(sql, con);
SqlDependency dep = new SqlDependency(cmd);
con.Open();
cmd.ExecuteNonQuery();
con.Close();
return dep;
}
private void button3_Click(object sender, EventArgs e)
{
GC.Collect();
GC.WaitForPendingFinalizers();
MessageBox.Show("Total Memory Usage = " + GC.GetTotalMemory(true).ToString());
}
private void button1_Click(object sender, EventArgs e)
{
bool exists = memCache.Get("a") != null;
MessageBox.Show("Value exits -> " + exists);
}
}
Чтобы использовать код, нажмите кнопку Button2 для инициализации, затем измените данные таблицы 2 в базе данных. используйте Button3 для просмотра доступной памяти.