【发布时间】:2011-10-17 06:43:03
【问题描述】:
我正在一个应用程序中使用 .NET 4.0 MemoryCache 类并尝试限制最大缓存大小,但在我的测试中,缓存似乎并未真正遵守限制。
我正在使用according to MSDN 应该限制缓存大小的设置:
- CacheMemoryLimitMegabytes:对象实例可以增长到的最大内存大小(以 MB 为单位)。”
- PhysicalMemoryLimitPercentage: "缓存可以使用的物理内存百分比,表示为1到100的整数值。默认为零,表示MemoryCache实例根据计算机上安装的内存量管理自己的内存1。" 1. 这并不完全正确——任何低于 4 的值都会被忽略并替换为 4。
我了解这些值是近似值而非硬性限制,因为清除缓存的线程每 x 秒触发一次,并且还取决于轮询间隔和其他未记录的变量。然而,即使考虑到这些差异,当第一个项目在设置 CacheMemoryLimitMegabytes 和 PhysicalMemoryLimitPercentage 一起或单独设置后从缓存中逐出时,我看到缓存大小非常不一致测试应用程序。为了确保我将每个测试运行了 10 次并计算了平均数字。
这些是在具有 3GB RAM 的 32 位 Windows 7 PC 上测试以下示例代码的结果。缓存的大小是在每次测试第一次调用 CacheItemRemoved() 之后获取的。 (我知道缓存的实际大小会比这个大)
MemLimitMB MemLimitPct AVG Cache MB on first expiry
1 NA 84
2 NA 84
3 NA 84
6 NA 84
NA 1 84
NA 4 84
NA 10 84
10 20 81
10 30 81
10 39 82
10 40 79
10 49 146
10 50 152
10 60 212
10 70 332
10 80 429
10 100 535
100 39 81
500 39 79
900 39 83
1900 39 84
900 41 81
900 46 84
900 49 1.8 GB approx. in task manager no mem errros
200 49 156
100 49 153
2000 60 214
5 60 78
6 60 76
7 100 82
10 100 541
这是测试应用程序:
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Runtime.Caching;
using System.Text;
namespace FinalCacheTest
{
internal class Cache
{
private Object Statlock = new object();
private int ItemCount;
private long size;
private MemoryCache MemCache;
private CacheItemPolicy CIPOL = new CacheItemPolicy();
public Cache(long CacheSize)
{
CIPOL.RemovedCallback = new CacheEntryRemovedCallback(CacheItemRemoved);
NameValueCollection CacheSettings = new NameValueCollection(3);
CacheSettings.Add("CacheMemoryLimitMegabytes", Convert.ToString(CacheSize));
CacheSettings.Add("physicalMemoryLimitPercentage", Convert.ToString(49)); //set % here
CacheSettings.Add("pollingInterval", Convert.ToString("00:00:10"));
MemCache = new MemoryCache("TestCache", CacheSettings);
}
public void AddItem(string Name, string Value)
{
CacheItem CI = new CacheItem(Name, Value);
MemCache.Add(CI, CIPOL);
lock (Statlock)
{
ItemCount++;
size = size + (Name.Length + Value.Length * 2);
}
}
public void CacheItemRemoved(CacheEntryRemovedArguments Args)
{
Console.WriteLine("Cache contains {0} items. Size is {1} bytes", ItemCount, size);
lock (Statlock)
{
ItemCount--;
size = size - 108;
}
Console.ReadKey();
}
}
}
namespace FinalCacheTest
{
internal class Program
{
private static void Main(string[] args)
{
int MaxAdds = 5000000;
Cache MyCache = new Cache(1); // set CacheMemoryLimitMegabytes
for (int i = 0; i < MaxAdds; i++)
{
MyCache.AddItem(Guid.NewGuid().ToString(), Guid.NewGuid().ToString());
}
Console.WriteLine("Finished Adding Items to Cache");
}
}
}
为什么 MemoryCache 不遵守配置的内存限制?
【问题讨论】:
-
for 循环错误,没有 i++
-
我已经为这个错误添加了一个 MS Connect 报告(也许其他人已经这样做了,但无论如何......)connect.microsoft.com/VisualStudio/feedback/details/806334/…
-
值得注意的是,微软现在(截至 2014 年 9 月)对上面链接的连接票证添加了相当彻底的响应。它的 TLDR 是 MemoryCache 不会在每个操作中固有地检查这些限制,而是仅在内部缓存修剪时遵守这些限制,这是基于动态内部计时器的周期性。
-
看起来他们更新了 MemoryCache.CacheMemoryLimit 的文档:“每次将新项目添加到 MemoryCache 实例时,MemoryCache 不会立即强制执行 CacheMemoryLimit。从 MemoryCache 驱逐额外项目的内部启发式方法会做到这一点逐渐……”msdn.microsoft.com/en-us/library/…
-
@Zeus,我认为 MSFT 解决了这个问题。无论如何,MSFT 在与我讨论后关闭了该问题,他们告诉我该限制仅在 PoolingTime 到期后应用。
标签: c# .net caching memorycache