如何清除System.Runtime.Caching.MemoryCache

Pet*_*rks 38 c# asp.net caching .net-4.0

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

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

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

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

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

然后我认为我应该可以调用.Dispose()整个缓存,但我不确定这是否是最佳方法,因为它的实现方式.

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

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

小智 34

起初我正在努力解决这个问题.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);
}
Run Code Online (Sandbox Code Playgroud)

  • 需要明确的是,Trim 采用*百分比*,而不是绝对计数,因此 Trim(100) 表示应该删除 100% 的项目——而不是 100 个项目。 (4认同)
  • 你绝对应该在这里添加线程同步.很惊讶你没有得到"在枚举时修改这个集合"的例外. (3认同)
  • 由于 [MemoryCache 实现 `GetEnumerator()` 的方式,这种用法不应引发 `IllegalOperationException`](http://referencesource.microsoft.com/#System.Runtime.Caching/System/Caching/MemoryCache.cs,d4a8840a7c5b83b9) . 它通过从内部存储复制数据来创建一个新的`Dictionary<string, object>`,并返回该新对象的枚举器,因此 MemoryCache 本身不会同时被枚举和修改。 (2认同)

ste*_*fan 17

如果您希望能够再使用它,则不应在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.作为缓存的本质:-)

  • 不幸的是,`Trim(100)`并不总是驱逐缓存中100%的项目:https://connect.microsoft.com/visualstudio/feedback/details/831755/memorycache-trim-method-doesnt-evict-100 -of-的项 (2认同)

Yas*_*ser 8

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

public void Flush()
{
    List<string> cacheKeys = MemoryCache.Default.Select(kvp => kvp.Key).ToList();
    foreach (string cacheKey in cacheKeys)
    {
        MemoryCache.Default.Remove(cacheKey);
    }
}
Run Code Online (Sandbox Code Playgroud)


Ron*_*del 7

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

处置现有的 MemoryCache 并创建一个新的 MemoryCache 对象。 /sf/answers/292832361/

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

var oldCache = Interlocked.Exchange(ref _existingCache, new MemoryCache("newCacheName"));
oldCache.Dispose();
Run Code Online (Sandbox Code Playgroud)

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