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

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

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

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内的元素输出出来,具体实现代码如下:

public static void Dump(this List<int> vs)
{
    string v= string.Join("--", vs);
    Console.WriteLine(v);
}

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

image.png

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

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();
}

修改后的输出结果如下:

image.png

总结:

MemoryCache背后其实就是ConcurrentDictionary,value其实是带着过期时间的CacheEntry,因此

在不过期并且没有发生变化的时候每次返回都是同一个缓存对象。作为缓存对象应进行只读操作,不应修改缓存对象,如需要修改应创建新对象而不是使用原来的对象。


目录
相关文章
|
3天前
|
测试技术
无法复现的bug,如何处理?
无法复现的bug,如何处理?
|
3天前
在代码优化过程中,常见的错误和bug包括以下几点
在代码优化过程中,常见的错误和bug包括以下几点
|
3天前
|
测试技术
如何高质量的做BUG分析
如何高质量的做BUG分析
26 0
|
8月前
|
安全 编译器 Go
读<一例 Go 编译器代码优化 bug 定位和修复解析>
读<一例 Go 编译器代码优化 bug 定位和修复解析>
83 0
|
XML 安全 数据格式
测试妹子提了个bug,为什么你多了个options请求?
对于简单请求来说,如果请求跨域,那么浏览器会放行让请求发出。浏览器会发出cors请求,并携带origin。此时不管服务端返回的是什么,浏览器都会把返回拦截,并检查返回的response的header中有没有Access-Control-Allow-Origin是否为true,说明资源是共享的,可以拿到。如果没有这个头信息,说明服务端没有开启资源共享,浏览器会认为这次请求失败终止这次请求,并且报错。
173 0
测试妹子提了个bug,为什么你多了个options请求?
|
存储 Web App开发 JSON
检查自己的代码是否存在内存泄露
造成内存泄露的根本原因就是我们写的代码中存在某些对象长期占用内存,得不到释放,且这个对象占用的内存会逐步增加,导致 v8 无法回收,从而造成的服务的异常和不稳定,甚至是服务的中断和崩溃。
253 0
检查自己的代码是否存在内存泄露
|
测试技术 Kotlin
【吐血🤮】一次生产环境NPE崩溃的排查记录(上)
直接说引起NPE的根本原因: rx订阅没有取消,回调时Fragment已经被回收,引用view调更新方法,自然NPE。
230 0
|
缓存 算法 安全
小师妹学JVM之:cache line对代码性能的影响
小师妹学JVM之:cache line对代码性能的影响
小师妹学JVM之:cache line对代码性能的影响
Drools 6.4.0Final版本KieScanner内存泄漏Bug
Drools 6.4.0Final版本KieScanner内存泄漏Bug
278 0
Drools 6.4.0Final版本KieScanner内存泄漏Bug
|
运维 Cloud Native 测试技术
高质量的缺陷分析:让自己少写 bug
缺陷分析做得好,bug 写得少。阿里资深技术专家和你分享如何进行高质量的缺陷分析,总结了 5 个要点,通过缺陷分析消除开发中的各种盲点,打造一个学习型的团队。
高质量的缺陷分析:让自己少写 bug