You need to enable JavaScript to run this app. ASP.NET高流量站点Gen2 GC过高问题排查及缓存项优化最佳实践
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET高流量站点Gen2 GC过高问题排查及缓存项优化最佳实践

问题根因确认

你观察到的高Gen2 GC问题确实和当前的缓存实现直接相关,原因如下:

  • 你设置的缓存过期时间为10分钟,远长于Gen0、Gen1的默认回收周期(通常Gen0回收间隔仅数秒到数十秒),缓存对象会在多次新生代回收后快速晋升到Gen2堆
  • HttpRuntime.Cache的过期清理机制为被动触发:只有访问过期key、或后台低频率的全局缓存扫描(默认间隔数分钟)时才会清理过期对象,过期的缓存对象会长期滞留在Gen2堆中,只能等到耗时最长的全堆Gen2 GC时才会被回收
  • 你提到的「Gen1中无存活对象」也完全符合这个特征:短生命周期的请求级对象都在Gen0就被回收,只有长存活的缓存对象会晋升到Gen2,Gen1自然没有持续存活的对象

现有代码的优化方案

1. 修复类型判断BUG

现有代码中的value.GetType() != typeof(T)存在逻辑漏洞:如果T是接口/抽象类、或可空值类型,实际存储的实现类/装箱后类型会导致判断误判,触发不必要的缓存重建,额外生成大量垃圾对象。修改方案如下:

// 替换原有类型判断逻辑
if (value == null || !(value is T typedValue))
{
    // 缓存重建逻辑
    // ...
    return data != null ? data.Data : default;
}
return typedValue;

2. 优化缓存实现

  • 替换HttpRuntime.Cache为System.Runtime.Caching.MemoryCache(.NET Framework 4.0+均支持,.NET Core/.NET 5+更推荐内置的Microsoft.Extensions.Caching.Memory.MemoryCache),新的缓存实现支持更灵活的清理策略、内存阈值触发回收、过期回调等能力,可大幅降低过期对象滞留的概率
  • 缓存时间计算使用DateTime.UtcNow替代DateTime.Now,避免服务器时区调整、时间同步等操作导致的缓存过期时间异常

3. 增加缓存击穿防护

高流量场景下如果缓存过期瞬间有大量请求命中同一个key,会同时触发getData()调用,瞬间生成大量重复的对象,这些对象大多还没插入缓存就成为垃圾,大幅加重GC负担。可添加按key的双检锁或限流逻辑:

// 可配合ConcurrentDictionary<key, SemaphoreSlim>实现同key单线程重建缓存
private static readonly ConcurrentDictionary<string, SemaphoreSlim> _keyLocks = new();
// 缓存重建前先获取对应key的锁,避免重复重建

4. 主动清理过期缓存

针对你10分钟更新一次赛事数据的业务特性,可以单独维护所有赛事相关的缓存key列表,每9分钟主动批量删除一次过期缓存,主动移除的对象如果还未晋升到Gen2,会直接在新生代GC中被回收,避免大量对象堆积到Gen2。


内容的提问来源于stack exchange,提问作者Mike Flynn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.20 22:06:07