3

我将 MemoryCache 与 Sql 依赖项一起使用。我注意到,当使用 MemoryCache.Set() 时,如果集合中的项目被覆盖,则会出现内存泄漏。考虑以下场景:

  1. 具有 key=A 的项被插入到缓存中,并依赖于 Table1
  2. 使用 .Set() 重新插入具有相同 key=a 的新项目,并依赖于 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 查看可用内存。

4

1 回答 1

0

大概过了很久才回复。

公共覆盖对象删除(字符串键,字符串 regionName = null);

在插入/替换缓存数据之前,您应该删除旧密钥。

于 2018-07-06T18:39:02.937 回答