最近有个需求需要定时清理服务器上所有的缓存。本来以为很简单的调用一下 MemoryCache.Clear 方法就完事了。谁知道 MemoryCache 类以及 IMemoryCache 扩展方法都没有 Clear 方法。这可给难住了,于是想找到所有的 Keys 来一个个 Remove ,谁知道居然也没有获取所有 Key 的方法。于是研究了一下 ,找到一些方法,下面介绍两个方法:

自定义 CacheWrapper 包装类

MemoryCache 构造 Entry 的时候支持传入 CancellationChangeToken 对象,当 CancellationChangeToken.Cancel 触发的时候会自动使该对象过期。那么我们只要对 MemoryCache 类包装一下很容易实现一个自己的 Cache 类。

 public class CacheWrapper
{
private readonly IMemoryCache _memoryCache;
private CancellationTokenSource _resetCacheToken = new(); public CacheWrapper(IMemoryCache memoryCache)
{
_memoryCache = memoryCache;
} public void Add(object key, object value, MemoryCacheEntryOptions memoryCacheEntryOptions)
{
using var entry = _memoryCache.CreateEntry(key);
entry.SetOptions(memoryCacheEntryOptions);
entry.Value = value; // add an expiration token that allows us to clear the entire cache with a single method call
entry.AddExpirationToken(new CancellationChangeToken(_resetCacheToken.Token));
} public object Get(object key)
{
return _memoryCache.Get(key);
} public void Remove(object key)
{
_memoryCache.Remove(key);
} public void Clear()
{
_resetCacheToken.Cancel(); // this triggers the CancellationChangeToken to expire every item from cache _resetCacheToken.Dispose(); // dispose the current cancellation token source and create a new one
_resetCacheToken = new CancellationTokenSource();
}
}

然后单元测试测试一下:


[TestMethod()]
public void ClearTest()
{
var memCache = new MemoryCache(new MemoryCacheOptions());
var wrapper = new CacheWrapper(memCache); for (int i = 0; i < 10; i++)
{
wrapper.Add(i.ToString(), new object(), new MemoryCacheEntryOptions());
} Assert.IsNotNull(wrapper.Get("1"));
Assert.IsNotNull(wrapper.Get("9")); wrapper.Clear(); for (int i = 0; i < 10; i++)
{
Assert.IsNull(wrapper.Get(i.ToString()));
} for (int i = 0; i < 10; i++)
{
wrapper.Add(i.ToString(), new object(), new MemoryCacheEntryOptions());
} Assert.IsNotNull(wrapper.Get("1"));
Assert.IsNotNull(wrapper.Get("9")); wrapper.Clear(); for (int i = 0; i < 10; i++)
{
Assert.IsNull(wrapper.Get(i.ToString()));
} }

测试通过。

Compact 方法

以上 CacheWrapper 类虽然可以实现我们想要的功能,但是对于原来的程序有侵入,需要使用 CacheWrapper 类替换默认的 MemoryCache 类,不是太好。于是不死心继续研究,后来直接看了 MemoryCache 的代码(源码在这),开源真香。发现 MemoryCache 有个 Compact 方法好像在干删除的勾当。也怪我英文不好,这单词是压缩的意思,居然才发现。。。。于是我们的清除所有对象的需求不就轻而易举了么?

 /// Remove at least the given percentage (0.10 for 10%) of the total entries (or estimated memory?), according to the following policy:
/// 1. Remove all expired items.
/// 2. Bucket by CacheItemPriority.
/// 3. Least recently used objects.
/// ?. Items with the soonest absolute expiration.
/// ?. Items with the soonest sliding expiration.
/// ?. Larger objects - estimated by object graph size, inaccurate.
MemoryCache.Compact(double percentage);

Compact 方法会对缓存的对象进行压缩,参数是个double,0.1 表示压缩 10% ,那么传 1.0 就是压缩 100%,那不就是 Clear All 么。所以我可以使用 Compact(1.0) 来清除所有的缓存对象。单元测试跑一下:

[TestMethod()]
public void CompactTest()
{
var memCache = new MemoryCache(new MemoryCacheOptions()); for (int i = 0; i < 10; i++)
{
memCache.Set(i.ToString(), new object(), new MemoryCacheEntryOptions());
} Assert.IsNotNull(memCache.Get("1"));
Assert.IsNotNull(memCache.Get("9")); memCache.Compact(1); for (int i = 0; i < 10; i++)
{
Assert.IsNull(memCache.Get(i.ToString()));
} for (int i = 0; i < 10; i++)
{
memCache.Set(i.ToString(), new object(), new MemoryCacheEntryOptions());
} Assert.IsNotNull(memCache.Get("1"));
Assert.IsNotNull(memCache.Get("9")); memCache.Compact(1); for (int i = 0; i < 10; i++)
{
Assert.IsNull(memCache.Get(i.ToString()));
}
}

完美通过。

这里简单介绍下 Compact 方法。根据注释它会按照已下优先级删除对象:

  1. 过期的对象
  2. CacheItemPriority 设置的优先级,等级越高越不容易被删除
  3. 最近最少被使用的对象
  4. 绝对过期时间
  5. 滑动过期时间
  6. 大对象

关注我的公众号一起玩转技术



MemoryCache 如何清除全部缓存?的更多相关文章

  1. Android手机清除微信缓存

    方法一: 1.任意找一个微信好友,给他发送网址 http://debugx5.qq.com 2.自己点击这个网址跳转 3.进入后看到下面的页面,通过勾选第二张截图的Cookie和文件缓存来清除微信缓存 ...

  2. 关于清除arp 缓存的那点事儿

    在Linux下,清除arp缓存表,例如: arp -d 10.0.3.6 我们可以用上面这条命令清除某一条记录,也可以用 arp -n |awk '/^[1-9]/{print "arp - ...

  3. iOS //清除本地缓存

    //清除本地缓存 -(void)clearCache{ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT ...

  4. Chrome清除dns缓存

    Chrome清除dns缓存 为了加快访问速度,Google Chrome浏览器采用了预提DNS记录,在本地建立DNS缓存的方法,加快网站的连接速度.你在谷歌Chrome浏览器的地址栏中输入about: ...

  5. SDWebImage清除图片缓存

    背景: 使用 SDWebImage 库,由于内存中一直缓存着加载的图片,而导致内存过高(我们无法手动管理内存),弹出内存警告而导致程序很卡或者直接crash掉. 我的解决方法: 在AppDelegat ...

  6. js清除浏览器缓存的几种方法

    2014年9月24日 4692次浏览 关于浏览器缓存 浏览器缓存,有时候我们需要他,因为他可以提高网站性能和浏览器速度,提高网站性能.但是有时候我们又不得不清除缓存,因为缓存可能误事,出现一些错误的数 ...

  7. 清除dns缓存

    Linux清除dns缓存命令 /etc/init.d/dnsmasq restart

  8. 如何清除DNS缓存,使用cmd命令清理DNS缓存方法

    如何清除DNS缓存,使用cmd命令清理DNS缓存方法 有时候电脑突然上不了网,或者存在某些网站打不开的情况,但别的网站又可以打开,解决办法需要清除DNS缓存,那么如何清除DNS缓存呢,最常用的方法就是 ...

  9. jquery是如何清除ajax缓存的

    大家都知道万恶的IE在ajax中往往只读取第一次ajax请求时候的数据,其余时候都是从cache提取数据,(太懒了T_T).原生的JS清除ajax缓存的方法多,但是终觉有点繁琐,如果是用jquery的 ...

随机推荐

  1. 面试官又整新活,居然问我for循环用i++和++i哪个效率高?

    原创:微信公众号 码农参上,欢迎分享,转载请保留出处. 前几天,一个小伙伴告诉我,他在面试的时候被面试官问了这么一个问题: 在for循环中,到底应该用 i++ 还是 ++i ? 听到这,我感觉这面试官 ...

  2. 【k8s】在AWS EKS部署并通过ALB访问k8s Dashboard保姆级教程

    本教程适用范围 在AWS上使用EKS服务部署k8s Dashboard,并通过ALB访问 EKS集群计算节点采用托管EC2,并使用启动模板. 使用AWS海外账号,us-west-2区域 使用账号默认v ...

  3. ound interface org.elasticsearch.common.bytes.BytesReference, but class was expected

    es得版本和本地项目不一致.. 配置es版本,现在使用得是5.2得版本,可是 maven上看到 elasticsearch-rest-high-level-client 最低也得6版本.下载安装高版本 ...

  4. mabatis的sql标签

    定义:mapper.xml映射文件中定义了操作数据库的sql,并且提供了各种标签方法实现动态拼接sql.每个sql是一个statement,映射文件是mybatis的核心. 一,内容标签 1.Name ...

  5. scanner对象,顺序及选择结构

    scanner对象 基本语法: Scanner s = new Scanner(System.in) 使用next()和nextLine()读取前,使用hasNext()和hasNextLine()来 ...

  6. 统计学习1:朴素贝叶斯模型(Numpy实现)

    模型 生成模型介绍 我们定义样本空间为\(\mathcal{X} \subseteq \mathbb{R}^n\),输出空间为\(\mathcal{Y} = \{c_1, c_2, ..., c_K\ ...

  7. 聊聊并发(六)——CAS算法

    一.原子类 1.CAS算法 强烈建议读者看这篇之前,先看这篇 初识JUC 的前两节,对原子性,原子变量,内存可见性有一个初步认识. CAS(Compare and Swap)是一种硬件对并发的支持,针 ...

  8. 洛谷 P4183 - [USACO18JAN]Cow at Large P(点分治)

    洛谷题面传送门 点分治 hot tea. 首先考虑什么样的点能够对以 \(u\) 为根的答案产生 \(1\) 的贡献.我们考虑以 \(u\) 为根对整棵树进行一遍 DFS.那么对于一个点 \(v\), ...

  9. Vue 中使用 TypeScript 详细总结

    VUE 项目中使用 Typescript 第一节:项目起步 Vue 中使用 TypeScript 项目中主要使用到的第三方依赖 vue2 vue-class-component vue-propert ...

  10. R同时保存png/pdf等格式图片

    R怎么同时保存png/pdf等多种格式的图片? 如果是ggplot对象,用ggsave用两下就行,如果不是呢? png/pdf()组合dev.off()是通常保存方法,但一个组合只能保存一个图片.要想 ...