Joh*_*ohn 5 .net c# caching windows-services memory-management
我试图找出应该如何使用MemoryCache以避免内存异常.我来自ASP.Net背景,其中缓存管理它自己的内存使用,所以我希望MemoryCache也会这样做.这似乎不是我所做的波纹管测试程序中所示的情况:
class Program
{
static void Main(string[] args)
{
var cache = new MemoryCache("Cache");
for (int i = 0; i < 100000; i++)
{
AddToCache(cache, i);
}
Console.ReadLine();
}
private static void AddToCache(MemoryCache cache, int i)
{
var key = "File:" + i;
var contents = System.IO.File.ReadAllBytes("File.txt");
var policy = new CacheItemPolicy
{
SlidingExpiration = TimeSpan.FromHours(12)
};
policy.ChangeMonitors.Add(
new HostFileChangeMonitor(
new[] { Path.GetFullPath("File.txt") }
.ToList()));
cache.Add(key, contents, policy);
Console.Clear();
Console.Write(i);
}
}
Run Code Online (Sandbox Code Playgroud)
在大约达到2GB的内存使用量(任何CPU)或消耗了我所有机器的物理内存(x64)(16GB)之后,上面引发内存不足异常.
如果我删除cache.Add位,该程序不会抛出任何异常.如果我在每次缓存添加后都包含对cache.Trim(5)的调用,我会看到它释放了一些内存,并且它在任何给定时间(从cache.GetCount())在缓存中保留了大约150个对象.
正在调用cache.Trim我的程序是否有责任?如果是这样的话什么时候应该被调用(比如我的程序怎么知道内存已经满了)?你如何计算百分比参数?
注意:我计划在长时间运行的Windows服务中使用MemoryCache,因此对其进行适当的内存管理至关重要.
MemoryCache 有一个后台线程,它定期估计进程正在使用多少内存以及缓存中有多少个键。当它认为您接近缓存内存限制时,它将修剪缓存。每次运行此后台线程时,它都会检查您与限制的接近程度,并且会在内存压力下增加轮询频率。
如果您非常快地添加项目,则后台线程没有机会运行,并且在缓存可以修剪和 GC 可以运行之前您可能会耗尽内存(在 x64 进程中,这可能会导致巨大的堆大小和多分钟的时间) GC 暂停)。众所周知,修剪进程/内存估计在某些情况下也存在错误。
如果您的程序由于快速加载过多的对象而容易出现内存不足,那么像 LRU 缓存这样具有有限大小的东西是一个更好的策略。LRU 通常使用基于项目计数的策略来逐出最近最少使用的项目。
我编写了 TLRU(一种时间感知最近最少使用策略)的线程安全实现,您可以轻松地将其用作 ConcurrentDictionary 的替代品。
它可以在 Github 上找到: https: //github.com/bitfaster/BitFaster.Caching
Install-Package BitFaster.Caching
Run Code Online (Sandbox Code Playgroud)
对于您的程序来说,使用它看起来就像这样,并且不会耗尽内存(取决于您的文件有多大):
class Program
{
static void Main(string[] args)
{
int capacity = 80;
TimeSpan timeToLive = TimeSpan.FromMinutes(5);
var lru = new ConcurrentTLru<int, byte[]>(capacity, timeToLive);
for (int i = 0; i < 100000; i++)
{
var value = lru.GetOrAdd(1, (k) => System.IO.File.ReadAllBytes("File.txt"));
}
Console.ReadLine();
}
}
Run Code Online (Sandbox Code Playgroud)
如果您确实想避免内存不足,还应该考虑将文件读入RecyclableMemoryStream中,并使用 BitFaster 中的 Scoped 类来使缓存值线程安全并避免处置时出现竞争。
| 归档时间: |
|
| 查看次数: |
1364 次 |
| 最近记录: |