使用LRU策略的默认内存缓存

问题描述:

我想在我的应用程序中实现一些缓存,我想在C#中使用默认内存缓存(如果不需要,可以更改此需求)。我的问题是,不想超过机器上的最大物理内存量,但据我所知,我无法将这种约束添加到默认内存缓存中。使用LRU策略的默认内存缓存

一般策略是:

  1. 如果对象已经在高速缓存10分钟,没有请求它被删除
  2. 如果一个新的对象被添加到所述高速缓存和最大量的avaliable物理内存接近使用元素基于LRU

我的缓存可以包含许多不同的对象和它们的范围从10MB到2-3gb删除,所以我真的不能得到trim功能工作。

是否有任何关于如何实现LRU缓存监测RAM的使用的建议?并且跳跃地使用.net中的缓存可以完成它?

编辑

我添加了一个简单的例子,其中的MemoryCache被限制为100MB和物理内存的20%,但是这不会改变任何东西。我的记忆充满了没有删除缓存条目。请注意,轮询间隔会更改为5秒钟。

class Item 
{ 
    private List<Guid> data; 

    public Item(int capacity) 
    { 
     this.data = new List<Guid>(capacity); 
     for (var i = 0; i < capacity; i++) 
      data.Add(Guid.NewGuid()); 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     var cache = new MemoryCache(
      "MyCache", 
      new NameValueCollection 
      { 
       { "CacheMemoryLimitMegabytes", "100" }, 
       { "PhysicalMemoryLimitPercentage", "20" }, 
       { "PollingInterval", "00:00:05" } 
      }); 

     for (var i = 0; i < 10000; i++) 
     { 
      var key = String.Format("key{0}", i); 
      Console.WriteLine("Add item: {0}", key); 
      cache.Set(key, new Item(1000000), new CacheItemPolicy() { UpdateCallback = UpdateHandler }); 
     } 

     Console.WriteLine("\nDone"); 
     Console.ReadKey(); 
    } 

    public static void UpdateHandler(CacheEntryUpdateArguments args) 
    { 
     Console.WriteLine("Remove: {0}, Reason: {1}", args.Key, args.RemovedReason.ToString()); 
    } 
} 

看起来像System.Runtime.Caching.MemoryCache类很适合这个法案。您可以在每个项目的基础上设置缓存策略,因此如果使用TimeSpan为10分钟的SlidingExpiration缓存策略添加项目,则应该获得您正在查找的行为。

这只是一个.Net v4类,所以它在早期的运行时版本上不存在。如果您处于Web上下文中,ASP.Net缓存的行为相似,但可能不会让您管理系统信息。

您可以设置当你创建缓存大小的限制,使其不超过一定的内存占用:

var myCache = new MemoryCache( 
    "MyCache", 
    new NameValueCollection { { "PhysicalMemoryLimit", "50" }} // set max mem pct 
    ); 

这应该防止任何分页到磁盘上,至少你的应用程序中。如果存在外部内存压力或者系统过度积极地将内存分页到磁盘,则缓存可能仍然被分页,但不是由于在应用程序内过度使用。据我所知,没有办法在C#中保留内存页面。

+0

这也是我的想法,如果我的机器有4 GB内存,并且我在4分钟内填充该缓存,那么当向缓存中添加更多对象时,缓存将切换到页面文件,而不是删除LRU对象。当滑动到期时,它会首先采取行动。 – aweis 2012-03-11 10:01:27

+0

我已经更新了答案,包括如何解决这个问题。大小限制将转储对象达到一个限制。分页无法完全防止。 – saarp 2012-03-11 18:47:12

+0

对于某些reasone,它不会更改属性值。在实例化之后查看缓存对象时,限制仍然是98! – aweis 2012-03-11 20:01:01