.net 4 Утечка MemoryCache?

Я использую MemoryCache с зависимостями Sql. Я заметил, что при использовании MemoryCache.Set() возникает утечка памяти, если элемент в коллекции переопределяется. Рассмотрим следующий сценарий:

  1. Элемент с ключом = A вставляется в кеш с зависимостью от Table1
  2. Новый элемент с тем же ключом = a повторно вставляется с использованием .Set() с зависимостью от Table2.
  3. Таблица2 изменилась в базе данных.

-> Item key=a действительно был удален из кеша, но его память по-прежнему востребована в MemoryCache. Память освобождается только тогда, когда данные для Table1 изменяются в базе данных.

Воспроизвести код:

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 для инициализации, затем измените данные Table2 в базе данных. используйте Button3, чтобы увидеть доступную память.


person Yair    schedule 28.03.2012    source источник


Ответы (1)


Вероятно, ответ на него спустя долгое время.

общедоступный объект переопределения Удалить (строковый ключ, строковое имя_региона = ноль);

Вы должны удалить старый ключ, прежде чем вставлять/заменять кешированные данные.

person Ziaullah Khan    schedule 06.07.2018