这是this question的后续行动,其中包含相互矛盾的答案。我也对与更新版本的ASP.NET相关的答案感兴趣。
我的应用程序使用HttpRuntime.Cache
来缓存一些永不过期的模型列表。它们在应用程序预热时被加载,它们很少被更改,但是经常阅读。
我的代码如下:
private void ReportRemovedCallback(string key, object value, CacheItemRemovedReason reason)
{
if (!ApplicationPoolService.IsShuttingDown())
{
var str = $"Removed cached item with key {key} and count {(value as IDictionary)?.Count}, reason {reason}";
LoggingService.Log(LogLevel.Info, str);
}
}
private IDictionary<int, T> ThreadSafeCacheAccessAction(Action<IDictionary<int, T>, bool> action = null)
{
// refresh cache if necessary
var dict = HttpRuntime.Cache[CacheDictKey] as IDictionary<int, T>;
bool invalidated = false;
if (dict == null)
{
lock (CacheLockObject)
{
// getting expiration times from model attribute
var cacheInfo = typeof(T).GetCustomAttributes(typeof(UseInCachedRepositoryAttribute), inherit: true).FirstOrDefault() as UseInCachedRepositoryAttribute;
int absoluteExpiration = cacheInfo?.AbsoluteExpiration ?? Constants.Cache.IndefiniteRetention;
int slidingExpiration = cacheInfo?.SlidingExpiration ?? Constants.Cache.NoSlidingExpiration;
dict = _modelRepository.AllNoTracking.ToList().Where(item => item.PkId != 0).ToDictionary(item => item.PkId, item => item);
HttpRuntime.Cache.Insert(CacheDictKey, dict, dependencies: null,
absoluteExpiration: DateTime.Now.AddMinutes(absoluteExpiration),
slidingExpiration: slidingExpiration <= 0 ? Cache.NoSlidingExpiration : TimeSpan.FromMinutes(slidingExpiration),
priority: CacheItemPriority.NotRemovable,
onRemoveCallback: ReportRemovedCallback);
invalidated = true;
}
}
根据提供的文档here,我还在web.config中包含了以下标记:
<caching>
<cache disableExpiration="true" disableMemoryCollection="true" />
</caching>
但是,有时会调用ReportRemovedCallback
来删除项目。我的感觉是忽略了web.config中的缓存配置(文档清楚地表明它已经过时),CacheItemPriority.NotRemovable
仅表示&#34;非常高的优先级&#34;,而不是&#34;永远不会删除&# 34。
问题: 有没有办法说服HttpRuntime.Cache永远不会删除某些项目?或者我应该考虑另一种缓存机制?
答案 0 :(得分:0)
好的,所以我挖的更多,而且没有明确的答案,但是this old docs的以下配置似乎适用于任何拒绝过期的试验:
未明确配置以下默认缓存元素 机器配置文件或根Web.config文件,但是 .NET中应用程序返回的默认配置 框架版本2.0。
<cache disableMemoryCollection="false"
disableExpiration="false" privateBytesLimit="0"
percentagePhysicalMemoryUsedLimit="90"
privateBytesPollTime="00:02:00" />
因此,如果物理内存使用率超过90%,它将驱逐缓存项。由于操作系统倾向于使用几乎所有物理内存来进行系统缓存(由任务管理器报告),因此听起来不太可能。
我花了MemoryCache进行旋转,因为它与HttpRuntime.Cache
非常相似。它提供了类似的功能,但缺少CacheEntryUpdateCallback
(你可以提供它,但如果它与null
不同则会引发InvalidArgumentException)。
现在我的代码如下:
var dict = MemoryCache.Default.Get(CacheDictKey) as IDictionary<int, T>;
if (dict == null)
{
lock (CacheLockObject)
{
// getting expiration times from model attribute
var cacheInfo = typeof(T).GetCustomAttributes(typeof(UseInCachedRepositoryAttribute), inherit: true).FirstOrDefault() as UseInCachedRepositoryAttribute;
int absoluteExpiration = cacheInfo?.AbsoluteExpiration ?? Constants.Cache.IndefiniteRetention;
int slidingExpiration = cacheInfo?.SlidingExpiration ?? Constants.Cache.NoSlidingExpiration;
dict = _modelRepository.AllNoTracking.ToList().Where(item => item.PkId != 0).ToDictionary(item => item.PkId, item => item);
var cacheItemPolicy = new CacheItemPolicy
{
AbsoluteExpiration = DateTime.Now.AddMinutes(absoluteExpiration),
SlidingExpiration = slidingExpiration <= 0 ? Cache.NoSlidingExpiration : TimeSpan.FromMinutes(slidingExpiration),
Priority = System.Runtime.Caching.CacheItemPriority.NotRemovable,
// throws InvalidArgumentException
// UpdateCallback = CacheEntryUpdateCallback
};
MemoryCache.Default.Add(CacheDictKey, dict, cacheItemPolicy);
}
}
经过一些测试后,没有额外删除,w3wp.exe
的内存消耗也按预期增加。
this answer中提供了更多详细信息。