C# 在ASP.NET中使用System.Runtime.Caching.MemoryCache会消耗大量内存
我正在asp.net应用程序中使用MemoryCache。在我的应用程序运行数小时后,w3wp进程会消耗大量内存,可以达到10GB的内存,之后应用程序会变得无响应,IIS会自动重置它(通过ping机制) 我分析了应用程序流程,发现MemoryCache在内部创建了MemoryCacheStore的多个实例(相当于CPU的数量),每个实例都会消耗大量内存 似乎出于某种原因,MemoryCache在多个实例中存储相同的数据,这会导致巨大的内存消耗 如下图所示,我有16个CPU,16个MemoryCacheStore是由单个MemoryCache实例在内部创建的。我检查了MemoryCache的源代码,发现它创建了一个环境MemoryCacheStore数组。处理器很重要,但没有发现为什么所有这些实例都使用内存,以及如何防止这种情况?C# 在ASP.NET中使用System.Runtime.Caching.MemoryCache会消耗大量内存,c#,asp.net-mvc-4,.net-4.0,C#,Asp.net Mvc 4,.net 4.0,我正在asp.net应用程序中使用MemoryCache。在我的应用程序运行数小时后,w3wp进程会消耗大量内存,可以达到10GB的内存,之后应用程序会变得无响应,IIS会自动重置它(通过ping机制) 我分析了应用程序流程,发现MemoryCache在内部创建了MemoryCacheStore的多个实例(相当于CPU的数量),每个实例都会消耗大量内存 似乎出于某种原因,MemoryCache在多个实例中存储相同的数据,这会导致巨大的内存消耗 如下图所示,我有16个CPU,16个MemoryCa
这就是内存缓存的工作——在内存中缓存数据。如果您使用了错误的键,或者将过期设置为无限,您将在内存中写入每条记录,永远不会重用任何内容,永远不会删除过时的数据。发布向
MemoryCache
添加项的代码、使用它的代码、缓存设置,特别是过期和内存限制。这里发布的信息没有用-它描述了任何类型的缓存应该做什么。MemoryCache可以配置为使用最大百分比的RAM,或者通过。解释默认值,例如x64系统的最小60%RAM或1TB。可能的重复也指出了问题的可能原因-使用默认限制创建太多MemoryCache实例。如果代码创建了12个MemoryCache实例,每个实例可以占用60%的RAM,那么它们的内存就会耗尽RAM@PanagiotisKanavos我已经添加了MemoryCacheManager类,并添加了如何使用它。请注意,我为我的应用程序创建了一个MemoryCacheManager实例,这就是内存缓存的工作—在内存中缓存数据。如果您使用了错误的键,或者将过期设置为无限,您将在内存中写入每条记录,永远不会重用任何内容,永远不会删除过时的数据。发布向MemoryCache
添加项的代码、使用它的代码、缓存设置,特别是过期和内存限制。这里发布的信息没有用-它描述了任何类型的缓存应该做什么。MemoryCache可以配置为使用最大百分比的RAM,或者通过。解释默认值,例如x64系统的最小60%RAM或1TB。可能的重复也指出了问题的可能原因-使用默认限制创建太多MemoryCache实例。如果代码创建了12个MemoryCache实例,每个实例可以占用60%的RAM,那么它们的内存就会耗尽RAM@PanagiotisKanavos我已经添加了MemoryCacheManager类,并添加了如何使用它。请注意,我为我的应用程序创建了一个MemoryCacheManager实例
public partial class MemoryCacheManager : DisposableObject, ICacheManager
{
const string LockRecursionExceptionMessage = "Acquiring identical cache items recursively is not supported. Key: {0}";
// Wwe put a special string into cache if value is null,
// otherwise our 'Contains()' would always return false,
// which is bad if we intentionally wanted to save NULL values.
public const string FakeNull = "__[NULL]__";
private readonly Work<ICacheScopeAccessor> _scopeAccessor;
private MemoryCache _cache;
private readonly ConcurrentDictionary<string, SemaphoreSlim> _keyLocks = new ConcurrentDictionary<string, SemaphoreSlim>();
public MemoryCacheManager(Work<ICacheScopeAccessor> scopeAccessor)
{
_scopeAccessor = scopeAccessor;
_cache = CreateCache();
}
private MemoryCache CreateCache()
{
return new MemoryCache("SmartStore" + DateTime.Now.ToString("yyyy_MM_dd_HH_mm_ss"));
}
public bool IsDistributedCache
{
get { return false; }
}
private bool TryGet<T>(string key, bool independent, out T value)
{
value = default(T);
object obj = _cache.Get(key);
if (obj != null)
{
// Make the parent scope's entry depend on this
if (!independent)
{
_scopeAccessor.Value.PropagateKey(key);
}
if (obj.Equals(FakeNull))
{
return true;
}
value = (T)obj;
return true;
}
return false;
}
public T Get<T>(string key, bool independent = false)
{
TryGet(key, independent, out T value);
return value;
}
public T Get<T>(string key, Func<T> acquirer, TimeSpan? duration = null, bool independent = false)
{
if (TryGet(key, independent, out T value))
{
return value;
}
if (_scopeAccessor.Value.HasScope(key))
{
throw new LockRecursionException(LockRecursionExceptionMessage.FormatInvariant(key));
}
// Get the (semaphore) locker specific to this key
using (KeyedLock.Lock("cache:" + key, TimeSpan.FromMinutes(1)))
{
// Atomic operation must be outer locked
if (!TryGet(key, independent, out value))
{
using (_scopeAccessor.Value.BeginScope(key))
{
value = acquirer();
Put(key, value, duration, _scopeAccessor.Value.Current.Dependencies);
return value;
}
}
}
return value;
}
public async Task<T> GetAsync<T>(string key, Func<Task<T>> acquirer, TimeSpan? duration = null, bool independent = false)
{
if (TryGet(key, independent, out T value))
{
return value;
}
if (_scopeAccessor.Value.HasScope(key))
{
throw new LockRecursionException(LockRecursionExceptionMessage.FormatInvariant(key));
}
// Get the async (semaphore) locker specific to this key
using (await KeyedLock.LockAsync("cache:" + key, TimeSpan.FromMinutes(1)))
{
if (!TryGet(key, independent, out value))
{
using (_scopeAccessor.Value.BeginScope(key))
{
value = await acquirer();
Put(key, value, duration, _scopeAccessor.Value.Current.Dependencies);
return value;
}
}
}
return value;
}
public void Put(string key, object value, TimeSpan? duration = null, IEnumerable<string> dependencies = null)
{
_cache.Set(key, value ?? FakeNull, GetCacheItemPolicy(duration, dependencies));
}
public bool Contains(string key)
{
return _cache.Contains(key);
}
public void Remove(string key)
{
_cache.Remove(key);
}
public IEnumerable<string> Keys(string pattern)
{
Guard.NotEmpty(pattern, nameof(pattern));
var keys = _cache.AsParallel().Select(x => x.Key);
if (pattern.IsEmpty() || pattern == "*")
{
return keys.ToArray();
}
var wildcard = new Wildcard(pattern, RegexOptions.IgnoreCase);
return keys.Where(x => wildcard.IsMatch(x)).ToArray();
}
public int RemoveByPattern(string pattern)
{
lock (_cache)
{
var keysToRemove = Keys(pattern);
int count = 0;
// lock atomic operation
foreach (string key in keysToRemove)
{
_cache.Remove(key);
count++;
}
return count;
}
}
public void Clear()
{
// Faster way of clearing cache: https://stackoverflow.com/questions/8043381/how-do-i-clear-a-system-runtime-caching-memorycache
var oldCache = Interlocked.Exchange(ref _cache, CreateCache());
oldCache.Dispose();
GC.Collect();
}
public virtual ISet GetHashSet(string key, Func<IEnumerable<string>> acquirer = null)
{
var result = Get(key, () =>
{
var set = new MemorySet(this);
var items = acquirer?.Invoke();
if (items != null)
{
set.AddRange(items);
}
return set;
});
return result;
}
private CacheItemPolicy GetCacheItemPolicy(TimeSpan? duration, IEnumerable<string> dependencies)
{
var absoluteExpiration = ObjectCache.InfiniteAbsoluteExpiration;
if (duration.HasValue)
{
absoluteExpiration = DateTime.UtcNow + duration.Value;
}
var cacheItemPolicy = new CacheItemPolicy
{
AbsoluteExpiration = absoluteExpiration,
SlidingExpiration = ObjectCache.NoSlidingExpiration
};
if (dependencies != null && dependencies.Any())
{
// INFO: we can only depend on existing items, otherwise this entry will be removed immediately.
dependencies = dependencies.Where(x => x != null && _cache.Contains(x));
if (dependencies.Any())
{
cacheItemPolicy.ChangeMonitors.Add(_cache.CreateCacheEntryChangeMonitor(dependencies));
}
}
//cacheItemPolicy.RemovedCallback = OnRemoveEntry;
return cacheItemPolicy;
}
//private void OnRemoveEntry(CacheEntryRemovedArguments args)
//{
// if (args.RemovedReason == CacheEntryRemovedReason.ChangeMonitorChanged)
// {
// Debug.WriteLine("MEMCACHE: remove depending entry '{0}'.".FormatInvariant(args.CacheItem.Key));
// }
//}
protected override void OnDispose(bool disposing)
{
if (disposing)
_cache.Dispose();
}
}
_requestCache.Get(key, () =>
{
var query = _categoryRepository.Table;
if (!showHidden)
query = query.Where(c => c.Published);
query = query.Where(c => c.ParentCategoryId == parentCategoryId && !c.Deleted);
query = ApplyHiddenCategoriesFilter(query, storeId, showHidden);
var categories = query.OrderBy(x => x.DisplayOrder).ToList();
return categories;
});