前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >分析一个错误使用MemoryCache导致的BUG

分析一个错误使用MemoryCache导致的BUG

作者头像
喵叔
发布2021-11-24 09:40:14
3990
发布2021-11-24 09:40:14
举报
文章被收录于专栏:喵叔's 专栏

这个Bug是我在项目中发现的,原因是MemoryCache使用不当造成了一个不小的Bug,虽说这个Bug很大部分人都知道,但是我觉得还是分享出来,记录一下。废话不多说,我们来看一下出错的代码(代码已经经过脱敏处理)

代码语言:javascript
复制
await using var services = 
	new ServiceCollection()
		.AddMemoryCache()
		.BuildServiceProvider();
GetValidValues(5).Dump();
GetValidValues(8).Dump();
List<int> GetValidValues(int valueInt)
{
    var memoryCache = services.GetRequiredService<IMemoryCache>();
    var vs= memoryCache.GetOrCreate("t1", entry =>
    {
        return Enumerable.Range(1, 10).ToList();
    });
    vs.RemoveAll(x => x > valueInt);
    return vs;
}

代码中Dump是扩展方法,它是把list内的元素输出出来,具体实现代码如下:

代码语言:javascript
复制
public static void Dump(this List<int> vs)
{
    string v= string.Join("--", vs);
    Console.WriteLine(v);
}

好了,来想一下上面的输出结果会是什么吧,期望的结果应该是每次都输出小于等于输入的值,实际是什么样的呢?实际输出结果如下:

从上图中第二次输出的结果是不是和你想的不一样呢,之所以出现上面问题是因为MemoryCache对象是直接保存在内存中的,缓存不变化时每次都返回同一个对象,如果发生了修改那么再次获取就是修改后的内容。因此正确做法是返回一个新对象而不是修改原来的对象,一个修改方法如下:

代码语言:javascript
复制
List<int> GetValidValues(int valueInt)
{
    var memoryCache = services.GetRequiredService<IMemoryCache>();
    var vs= memoryCache.GetOrCreate("t1", entry =>
    {
        return Enumerable.Range(1, 10).ToList();
    });
    return vs.Where(v => v <= valueInt).ToList();
}

修改后的输出结果如下:

总结:

MemoryCache背后其实就是ConcurrentDictionary,value其实是带着过期时间的CacheEntry,因此 在不过期并且没有发生变化的时候每次返回都是同一个缓存对象。作为缓存对象应进行只读操作,不应修改缓存对象,如需要修改应创建新对象而不是使用原来的对象。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/11/22 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档