如何清除System.Runtime.Caching.MemoryCache

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何清除System.Runtime.Caching.MemoryCache相关的知识,希望对你有一定的参考价值。

我使用System.Runtime.Caching.MemoryCache来保存永不过期的物品。但是,有时我需要能够清除整个缓存。我怎么做?

我问了一个类似的问题here关于我是否可以枚举缓存,但这是一个坏主意,因为它需要在枚举期间同步。

我尝试过使用.Trim(100),但这根本不起作用。

我已经尝试通过Linq获取所有密钥的列表,但后来我回到了我开始的地方,因为一个接一个地逐出项目很容易导致竞争条件。

我想存储所有的密钥,然后为每个密钥发出一个.Remove(key),但是那里也有一个隐含的竞争条件,所以我需要锁定对密钥列表的访问,然后事情再次变得混乱。

然后我认为我应该能够在整个缓存上调用.Dispose(),但我不确定这是否是最好的方法,因为它的实现方式。

使用ChangeMonitors不是我的设计的选项,并且对于这样一个微不足道的要求是不必要的复杂。

那么,我该如何彻底清除缓存呢?

答案

如果您希望能够再使用它,则不应在MemoryCache的Default成员上调用dispose:

设置高速缓存的状态以指示高速缓存被释放。任何调用更改缓存状态的公共缓存方法的尝试(例如添加,删除或检索缓存条目的方法)都可能导致意外行为。例如,如果在释放缓存后调用Set方法,则会发生no-op错误。如果您尝试从缓存中检索项目,Get方法将始终返回Nothing。 http://msdn.microsoft.com/en-us/library/system.runtime.caching.memorycache.dispose.aspx

关于Trim,它应该工作:

Trim属性首先删除超过绝对或滑动到期的条目。为已删除的项目注册的任何回调都将传递已删除的已过期原因。

如果删除过期的条目不足以达到指定的修剪百分比,则将根据最近最少使用(LRU)算法从缓存中删除其他条目,直到达到请求的修剪百分比。

但另外两个用户报告它在同一页面上不起作用,所以我猜你会被删除()http://msdn.microsoft.com/en-us/library/system.runtime.caching.memorycache.trim.aspx

更新然而,我没有看到它是单例或其他不安全的多个实例,所以你应该能够覆盖你的引用。

但是,如果您需要从Default实例中释放内存,则必须手动清除它或通过dispose永久销毁它(使其无法使用)。

基于你的问题,你可以让你自己的单独强加类返回一个你可以随意内部处理的Memorycache。作为缓存的本质:-)

另一答案

起初我正在努力解决这个问题。 MemoryCache.Default.Trim(100)不起作用(如上所述)。修剪是最佳尝试,因此如果缓存中有100个项目,并且您调用Trim(100)它将删除最少使用的项目。

修剪返回删除的项目数,大多数人希望删除所有项目。

在我的带有MemoryCache.Default的xUnit测试中,此代码为我删除了MemoryCache中的所有项目。 MemoryCache.Default是默认的Region。

foreach (var element in MemoryCache.Default)
{
    MemoryCache.Default.Remove(element.Key);
}
另一答案

这就是我为我正在做的事情所做的......

public void Flush()
{
    List<string> cacheKeys = MemoryCache.Default.Select(kvp => kvp.Key).ToList();
    foreach (string cacheKey in cacheKeys)
    {
        MemoryCache.Default.Remove(cacheKey);
    }
}
另一答案

@ stefan的答案详细说明了原理;这是我怎么做的。

应该在重新创建缓存时同步对缓存的访问,以避免客户端代码在处置之后,但在重新创建之前访问缓存的竞争条件。

要避免此同步,请在适配器类(包装MemoryCache)中执行此操作:

public void clearCache() {
  var oldCache = TheCache;
  TheCache = new MemoryCache("NewCacheName", ...);
  oldCache.Dispose();
  GC.Collect();
}

这样,TheCache始终处于非处置状态,不需要同步。

另一答案

我知道这是一个古老的问题,但我遇到的最好的选择是

处理现有的MemoryCache并创建一个新的MemoryCache对象。 https://stackoverflow.com/a/4183319/880642

答案并没有真正提供以线程安全方式执行此操作的代码。但这可以使用Interlocked.Exchange来实现

var oldCache = Interlocked.Exchange(ref _existingCache, new MemoryCache("newCacheName"));
oldCache.Dispose();

这将使用新缓存交换现有缓存,并允许您在原始缓存上安全地调用Dispose。这避免了需要枚举缓存中的项目以及在使用缓存时导致的竞争条件。

另一答案

我也遇到了这个问题。 .Dispose()做了一些与我的预期完全不同的事情。

相反,我在控制器类中添加了一个静态字段。我没有使用默认缓存来绕过这种行为,但创建了一个私有缓存(如果你想调用它)。所以我的实现看起来有点像这样:

public class MyController : Controller
{

    static MemoryCache s_cache = new MemoryCache("myCache");

    public ActionResult Index()
    {

        if (conditionThatInvalidatesCache)
        {
            s_cache = new MemoryCache("myCache");
        }

        String s = s_cache["key"] as String;

        if (s == null)
        {
            //do work
            //add to s_cache["key"]
        }

        //do whatever next
    }
}
另一答案

查看this帖子,特别是Thomas F. Abraham发布的答案。它有一个解决方案,使您可以清除整个缓存或命名子集。

这里的关键是:

// Cache objects are obligated to remove entry upon change notification.
base.OnChanged(null);

我自己实现了这一点,一切似乎都很好。

以上是关于如何清除System.Runtime.Caching.MemoryCache的主要内容,如果未能解决你的问题,请参考以下文章

Echarts如何清除上一次加载的数据

如何清除MySQL复制

为何要清除浮动?如何清除?

如何清除JS创建的DIV?

怎么清除浏览器缓存 如何清除浏览器缓存方法

如何清除chrome浏览器上的缓存