C#中Microsoft.Extensions.Caching.Memory 与 System.Runtime.Caching.MemoryCache区别
Microsoft.Extensions.Caching.Memory 和 System.Runtime.Caching.MemoryCache 都是.NET中的内存缓存实现,但它们的设计初衷、演进背景、使用场景和定位都有明显区别。总结如下:
一、基本区别
| 特性 | System.Runtime.Caching.MemoryCache | Microsoft.Extensions.Caching.Memory (IMemoryCache) |
|---|---|---|
| 命名空间 | System.Runtime.Caching | Microsoft.Extensions.Caching.Memory |
| 首次出现 | .NET Framework 4.0 | ASP.NET Core 1.0 (随 .NET Core 推出) |
| 主要面向 | 传统的 .NET Framework 应用 | 跨平台的 .NET Core / ASP.NET Core 应用 |
| 是否跨平台 | 不完全跨平台(主要支持 Windows) | 完全跨平台 (.NET Core 及以后版本跨Windows、Linux、macOS) |
| 默认缓存实例 | 使用 MemoryCache.Default 单例 |
需要自己创建实例或通过DI注入 |
| 配置复杂度 | 功能强大,支持多种策略、缓存优先级、内存压力管理等 | 设计轻量简单,易于拓展 |
| 依赖关系 | 依赖 Windows 组件,如 Memory Management |
纯托管,无外部依赖 |
二、为什么有两个?为什么不统一?
1. .NET 演进与跨平台需求
System.Runtime.Caching.MemoryCache是为 .NET Framework 设计,早期只支持 Windows 平台,依赖 Windows API 实现复杂缓存管理和回收,适合桌面应用和传统服务器应用。- 随着 .NET Core 的出现和跨平台战略,微软设计了
Microsoft.Extensions.Caching.Memory,完全由托管代码实现,易于跨平台使用,适配现代的轻量级 web 和云原生应用。
2. 设计理念不同
System.Runtime.Caching设计复杂,提供丰富的缓存过期机制、内存压力响应回收策略等,功能偏向完整的企业级缓存中间件。Microsoft.Extensions.Caching.Memory更注重简单易用、灵活可扩展,集成在 .NET Core 的依赖注入(DI)和配置体系中。
3. 生态和使用场景分离
System.Runtime.Caching.MemoryCache仍在一些传统 .NET Framework 应用中使用广泛,特别是需要依赖 Windows 特性的场景。Microsoft.Extensions.Caching.Memory是 ASP.NET Core 的“官方”缓存实现,推荐用于新开发、跨平台、微服务、Cloud Native 的场景。
三、具体差异示例
| 特性 | System.Runtime.Caching.MemoryCache | Microsoft.Extensions.Caching.Memory |
|---|---|---|
| 过期设置 | 通过 CacheItemPolicy.AbsoluteExpiration |
通过 MemoryCacheEntryOptions.SetAbsoluteExpiration |
| 失效回调 | CacheEntryRemovedCallback |
MemoryCacheEntryOptions.RegisterPostEvictionCallback |
| 支持优先级、内存压力感知 | 支持(高、中、低等优先级和内存压力驱动回收) | 没有内存压力感知,手动控制或结合其他机制 |
| 多缓存实例管理 | 支持通过不同名字创建多个 MemoryCache 实例 |
缺省只有创建自己实例或依赖注入管理 |
| 支持文件依赖、监视变更? | 支持文件依赖和 ChangeMonitors | 支持通过 IChangeToken 实现 |
| 性能 | 较重,功能齐全 |
高性能,轻量级
|
四、总结
| 选择指南 |
|---|
新项目(尤其 .NET Core / .NET 5+)推荐使用 Microsoft.Extensions.Caching.Memory |
| 它更加轻量、跨平台,集成简便,适合现代应用。 |
传统 .NET Framework 项目且需要更复杂缓存策略时,可以使用 System.Runtime.Caching.MemoryCache |
| 如需内存压力响应机制或兼容老代码。 |
五、参考
如果你的应用代码是基于 ASP.NET Core 或需要跨平台,建议使用 Microsoft.Extensions.Caching.Memory。如果是老的 .NET Framework 应用,可继续用 System.Runtime.Caching.MemoryCache。
注意:MemoryCache的过期时间回调是惰性的,不会主动去触发回调,只有
-
你调用了缓存的访问方法(
Get、TryGetValue…)时,触发对过期键的排查并且调用回调; -
或者有内存缓存后台线程检测到过期键。
换句话说,如果到期时间到了,但你没做访问,回调可能不会立刻执行。
为了主动去触发过期回调,请使用如下添加如下类似的代码主动去触发:
DateTime expireTime = order.TimeExpire.GDCToDateTime(); // 2026/9/17 17:26:02 var cacheEntryOptions = new MemoryCacheEntryOptions() { AbsoluteExpiration = new DateTimeOffset(expireTime) }; cacheEntryOptions.RegisterPostEvictionCallback((key, value, reason, state) => { Console.WriteLine($"缓存过期回调触发,订单号={key}, 原因={reason}"); expiryCallBack(key.ToString()); }); _cache.Set(order.OrderNumber, order.OrderNumber, cacheEntryOptions); Console.WriteLine($"缓存添加成功,过期时间: {expireTime}"); Task.Run(async () => { while(true) { if(_cache.TryGetValue(order.OrderNumber, out var val)) //触发对过期键的排查并且调用回调 { Console.WriteLine($"缓存仍有效,Key={order.OrderNumber}"); } else { Console.WriteLine($"缓存已过期,Key={order.OrderNumber}"); break; } await Task.Delay(5000); // 5秒访问一次,这个时间可以根据实际需求来更改。 譬如:可以改成 过期的时间点来触发,减少触发频率 } });
结论
| 特点 | 说明 |
|---|---|
| 过期回调延迟 | 存在,通常几秒级,取决于访问频率和后台扫描间隔 |
| 精确定时需求 | 不满足,建议使用专门定时调度机制 |
| 内存缓存过期回调适用场景 | 缓存无效后跟进清理、日志、辅助操作等不要求精确时序的场景 |
浙公网安备 33010602011771号