如何清除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的主要内容,如果未能解决你的问题,请参考以下文章