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

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

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

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

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

这是一个丑陋的实现细节,微软根本不想公开。 在.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); } } 

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

我使用原始代码并进行了一些小调整,我使用“_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); } } 

作为替代方案,您还可以实现IMemoryCacheManager接口并将其分配给全局ObjectCache.Host属性。 这要求你被允许这样做,即你的应用程序中没有其他组件已经这样做了(ASP.NET浮现在脑海中,但我不确定)。 就个人而言,我在控制台/ Windows服务应用程序中使用该方法没有任何问题。

另请注意,您只能在完整GC之后获得缓存大小,但这与Hans的方法不应有任何不同。

另请注意,下面的代码适用于命名的MemoryCaches,即不适用于实例本身。

相当一种观点“但是”。 但是,它不需要反思。

所以,这是代码。

 public static class MemoryCacheHelper { private static readonly MemoryCacheServiceProvider s_serviceProvider = new MemoryCacheServiceProvider(); static MemoryCacheHelper() { try { ObjectCache.Host = s_serviceProvider; } catch (InvalidOperationException ex) { // ObjectCache.Host can only be set once. } } public static MemoryCache Create(string name, NameValueCollection config) { return new MemoryCache(name, config); } // Return approximate cache size and when that value was last determined. public static Tuple GetApproximateSize(string name) { return s_serviceProvider.GetApproximateSize(cache.Name); } private class MemoryCacheServiceProvider : IMemoryCacheManager, IServiceProvider { private readonly object m_lock = new object(); private readonly IDictionary> m_sizes = new Dictionary>(); public Tuple GetApproximateSize(string name) { lock (m_lock) { Tuple info; if (m_sizes.TryGetValue(name, out info)) return info; return null; } } void IMemoryCacheManager.UpdateCacheSize(long size, MemoryCache cache) { lock (m_lock) { // The UpdateCacheSize() method will be called based on the configured "pollingInterval" // for the respective cache. That value defaults to 2 minutes. So this statement doesn't // fire to often and as a positive side effect we get some sort of "size-heartbeat" which // might help when troubleshooting. m_sizes[cache.Name] = Tuple.Create(size, DateTime.UtcNow); } } void IMemoryCacheManager.ReleaseCache(MemoryCache cache) { lock (m_lock) { m_sizes.Remove(cache.Name); } } object IServiceProvider.GetService(Type serviceType) { if (serviceType == typeof(IMemoryCacheManager)) { return this; } return null; } } 

如果你在性能方面寻找内存,你需要使用一些计数器,如:

所有堆中的字节数

保留字节总数

您可以使用Perfmon执行此操作,您可以参考此链接:

http://msdn.microsoft.com/en-us/library/x2tyfybc(v=vs.110).aspx

但通过这种方式测量并不简单,但你会有很好的洞察力。

罗伯托