You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何获取System.Runtime.Caching.MemoryCache当前缓存大小及使用率

查询System.Runtime.Caching.MemoryCache实时内存使用占比的方法

官方公开API没有直接暴露实时内存使用量的查询接口,但是MemoryCache内部本身维护了内存使用的估算统计值,可以通过反射读取内部字段计算占比,以下是可直接落地的实现方案。

核心实现逻辑

  • MemoryCache内部通过私有字段维护当前缓存的近似内存占用值,这个值也是框架本身触发内存淘汰逻辑的判断依据,统计精度足够用于占比计算。
  • 缓存实际生效的内存上限是CacheMemoryLimitMegabytes配置的私有内存阈值、PhysicalMemoryLimitPercentage配置的物理内存占比阈值两者的最小值,任意一个阈值触发都会启动缓存淘汰。
  • 通过反射读取内部字段时提前缓存反射元数据,避免每次查询重复执行反射操作产生性能损耗。

可直接复用的代码

using System;
using System.Reflection;
using System.Runtime.Caching;

public static class MemoryCacheExtensions
{
    // 提前缓存反射获取的字段、方法元数据,降低性能开销
    private static readonly FieldInfo _sizedRefField = typeof(MemoryCache).GetField("_sizedRef", BindingFlags.Instance | BindingFlags.NonPublic);
    private static readonly MethodInfo _approximateSizeMethod = _sizedRefField?.FieldType.GetMethod("GetApproximateSize", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
    private static readonly FieldInfo _cacheMemoryLimitField = typeof(MemoryCache).GetField("_cacheMemoryLimit", BindingFlags.Instance | BindingFlags.NonPublic);
    private static readonly FieldInfo _physicalMemoryLimitField = typeof(MemoryCache).GetField("_physicalMemoryLimit", BindingFlags.Instance | BindingFlags.NonPublic);

    /// <summary>
    /// 获取当前缓存估算的已使用内存字节数
    /// </summary>
    public static long GetCurrentMemoryUsageBytes(this MemoryCache cache)
    {
        if (cache == null) throw new ArgumentNullException(nameof(cache));
        if (_sizedRefField == null || _approximateSizeMethod == null)
            throw new NotSupportedException("当前运行时版本不支持读取MemoryCache内存统计值");
        
        var sizedRef = _sizedRefField.GetValue(cache);
        if (sizedRef == null) return 0;
        long size = (long)_approximateSizeMethod.Invoke(sizedRef, null);
        return size < 0 ? 0 : size;
    }

    /// <summary>
    /// 获取当前缓存实际生效的内存上限字节数
    /// </summary>
    public static long GetEffectiveMemoryLimitBytes(this MemoryCache cache)
    {
        if (cache == null) throw new ArgumentNullException(nameof(cache));
        long configMemLimit = _cacheMemoryLimitField?.GetValue(cache) is long limit1 ? limit1 : long.MaxValue;
        long physicalMemLimit = _physicalMemoryLimitField?.GetValue(cache) is long limit2 ? limit2 : long.MaxValue;
        return Math.Min(configMemLimit, physicalMemLimit);
    }

    /// <summary>
    /// 获取当前缓存已使用内存占生效上限的比例,返回值范围0~1
    /// </summary>
    public static double GetMemoryUsageRatio(this MemoryCache cache)
    {
        long used = cache.GetCurrentMemoryUsageBytes();
        long limit = cache.GetEffectiveMemoryLimitBytes();
        if (limit <= 0) return 0;
        double ratio = (double)used / limit;
        return ratio > 1 ? 1 : ratio;
    }
}

使用方式

直接在MemoryCache实例上调用扩展方法即可,支持默认实例和自定义命名实例:

// 查询默认内存缓存实例的使用占比
double usageRatio = MemoryCache.Default.GetMemoryUsageRatio();
// 换算为百分比:usageRatio * 100

// 单独查询已使用字节数、上限字节数
long usedBytes = MemoryCache.Default.GetCurrentMemoryUsageBytes();
long limitBytes = MemoryCache.Default.GetEffectiveMemoryLimitBytes();

注意事项

  • 拿到的内存使用量是近似估算值,不是字节级精确统计。这是MemoryCache的原生设计:写入条目时累加估算的条目大小,移除条目时扣减对应大小,不会实时遍历对象计算精确内存占用,框架自带的内存淘汰逻辑也是基于这个估算值运行,完全可以满足监控内存占用水平的需求。
  • 上述代码适配.NET Framework 4.7+、.NET Core 3.1、.NET 5/6/7版本,如果后续大版本更新修改了内部私有字段命名,只需要对应调整反射读取的字段名即可,核心逻辑不变。
  • 不要过于频繁调用查询方法,建议监控场景下间隔数秒查询一次即可,虽然反射开销已经被缓存,但过于频繁的查询还是会产生不必要的性能消耗。

内容的提问来源于stack exchange,提问作者Tiger Galo

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 20:39:19