首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >MemoryCache OutOfMemoryException

MemoryCache OutOfMemoryException
EN

Stack Overflow用户
提问于 2014-05-31 19:09:01
回答 1查看 2.1K关注 0票数 6

我正在尝试弄清楚应该如何使用MemoryCache,以避免出现内存不足异常。我来自ASP.Net后台,缓存管理它自己的内存使用情况,所以我希望MemoryCache也会做同样的事情。这似乎不是我在下面的测试程序中所说明的情况:

代码语言:javascript
复制
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);
    }        
}

在大约达到2 2GB的内存使用量(任何CPU)或耗尽我机器的所有物理内存(X64)(16 2GB)之后,上面的代码抛出内存不足异常。

如果我删除cache.Add位,程序也不会抛出异常。如果我在每次添加缓存后都包含对cache.Trim(5)的调用,我会看到它释放了一些内存,并且在任何给定的时间(从cache.GetCount()),它在缓存中保留了大约150个对象。

调用cache.Trim是我的程序的责任吗?如果是这样的话,什么时候应该调用它(比如我的程序怎么知道内存已经满了)?如何计算百分比参数?

注意:我计划在一个长时间运行的windows服务中使用MemoryCache,所以对它进行适当的内存管理是至关重要的。

EN

回答 1

Stack Overflow用户

发布于 2020-06-18 15:07:15

MemoryCache有一个后台线程,它定期估计进程使用了多少内存以及缓存中有多少键。当它认为你正在接近cachememorylimit时,它会裁剪缓存。每次运行这个后台线程时,它都会检查您是否接近限制,并且会在内存紧张的情况下增加轮询频率。

如果您以非常快的速度添加项,后台线程将没有机会运行,并且您可能会在缓存清理和GC运行之前耗尽内存(在x64进程中,这可能会导致巨大的堆大小和数分钟的GC暂停)。已知的trim过程/内存估计也具有bugs under some conditions

如果您的程序由于快速加载过多的对象而容易出现内存不足的情况,那么LRU缓存之类的有限制大小的对象是一种更好的策略。LRU通常使用基于项目计数的策略来驱逐最近最少使用的项目。

我写了一个线程安全的TLRU实现(一种时间感知的最近最少使用的策略),你可以很容易地使用它作为ConcurrentDictionary的替代。

它可以在Github上找到:https://github.com/bitfaster/BitFaster.Caching

代码语言:javascript
复制
Install-Package BitFaster.Caching

在你的程序中使用它看起来就像这样,它不会耗尽内存(取决于你的文件有多大):

代码语言:javascript
复制
 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();
    }
 }

如果您确实希望避免内存不足,还应该考虑将文件读取到RecyclableMemoryStream中,并使用BitFaster中的作用域类来确保缓存值的线程安全,并避免dispose上的竞争。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/23969334

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档