如何衡量.NET Memory Cache 4.0的当前大小?

Raj*_*dar 23 .net c#

目前我们正在使用.NET Memory Cache 4.0来满足缓存要求.(不是ASP.NET缓存,不是任何外部缓存)

查看".NET内存缓存4.0"性能计数器,有关于缓存命中,未命中,条目,修剪等的数据,但与大小无关.

是否有一种方法可以测量/了解生产应用程序使用的高速缓存的当前大小

我希望能够在不同的时间点捕获这些数据并获得缓存的平均大小.

Han*_*ant 23

这是一个丑陋的实现细节,微软根本不想公开.在.NET中测量对象大小通常是不可能的.MemoryCache使用一个相当讨厌的后门来实现其内存限制触发器,它使用CLR的DACCESS组件,实际上旨在帮助实现内存分析器.

你可以用调试器看到它​​,所以它不像你无法达到它.你只需编写非常难看的代码来挖掘私有领域:

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

public static class MemoryCacheHackExtensions {
    public static long GetApproximateSize(this MemoryCache cache) {
        var statsField = typeof(MemoryCache).GetField("_stats", BindingFlags.NonPublic | BindingFlags.Instance);
        var statsValue = statsField.GetValue(cache);
        var monitorField = statsValue.GetType().GetField("_cacheMemoryMonitor", BindingFlags.NonPublic | BindingFlags.Instance);
        var monitorValue = monitorField.GetValue(statsValue);
        var sizeField = monitorValue.GetType().GetField("_sizedRef", BindingFlags.NonPublic | BindingFlags.Instance);
        var sizeValue = sizeField.GetValue(monitorValue);
        var approxProp = sizeValue.GetType().GetProperty("ApproximateSize", BindingFlags.NonPublic | BindingFlags.Instance);
        return (long)approxProp.GetValue(sizeValue, null);
    }
}
Run Code Online (Sandbox Code Playgroud)

似乎在.NET 4.6.1上工作得很好,没有经过广泛测试.这是可以获得的土地,只是不依赖它,因为它可能打破任何.NET更新.


Sha*_*zan 8

我使用了原始代码并且必须进行微调,我使用"_sizedRefMultiple"而不是"_sizedRef"来使其与.NET 4.6一起使用.

public static class MemoryCacheHackExtensions
{
    public static long GetApproximateSize(this MemoryCache cache)
    {
        var statsField = typeof(MemoryCache).GetField("_stats", BindingFlags.NonPublic | BindingFlags.Instance);
        var statsValue = statsField.GetValue(cache);
        var monitorField = statsValue.GetType().GetField("_cacheMemoryMonitor", BindingFlags.NonPublic | BindingFlags.Instance);
        var monitorValue = monitorField.GetValue(statsValue);
        var sizeField = monitorValue.GetType().GetField("_sizedRefMultiple", BindingFlags.NonPublic | BindingFlags.Instance);
        var sizeValue = sizeField.GetValue(monitorValue);
        var approxProp = sizeValue.GetType().GetProperty("ApproximateSize", BindingFlags.NonPublic | BindingFlags.Instance);
        return (long)approxProp.GetValue(sizeValue, null);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 也必须在 .NET 4.5 上使用相同的技巧 ' var sizeVarName = "_sizedRef"; #if NET45 sizeVarName = "_sizedRefMultiple"; #万一 ' (2认同)

Mis*_*sky 5

最后,在 .NET 7 预览版中,您可以非常轻松地访问该度量。添加了一些新指标IMemoryCache

  • MemoryCacheStatistics保存缓存命中/未命中/估计大小和计数IMemoryCache
  • GetCurrentStatistics返回 的实例MemoryCacheStatistics,或者在TrackStatistics未启用标志时返回 null。该库有一个可用于MemoryCache.

在这里阅读更多内容。