Context.Cache是​​否可能在请求中删除项目?

时间:2012-10-19 21:58:59

标签: c# asp.net .net caching iis

假设我有一个类似下面的代码片段,它返回Context.Cache [“someComplexObject”]的内容:

public class Something {
    private static SortedDictionary<Guid, Object> ComplexObjectCache
    {
        get
        {
            if (Context.Cache["someComplexObject"] == null)
            {
                FillCache();
            }
            return (SortedDictionary<Guid, Object>)Context.Cache["someComplexObject"];
        }

        set
        {
            Int32 seconds = (new Random()).Next(120, 180);
            Context.Cache.Add(
                "someComplexObject",
                value,
                null,
                DateTime.Now.AddSeconds(seconds),
                System.Web.Caching.Cache.NoSlidingExpiration,
                System.Web.Caching.CacheItemPriority.NotRemovable,
                null
            );
        }
    }
}

在用户控件中,假设我有:

Object o = Something.ComplexObjectCache[someGuid];

/* 

    do some other stuff ...

*/

DoSomethingWith(o);

偶尔会出现非常罕见的情况,当我看到 DoSomethingWith(o)被击中时,我会看到异常会让我相信 o 不再在记忆中。我97%确定没有其他并行进程发生,除了缓存正在做什么。我看到其他奇怪的现象会让我相信缓存密钥是空的还是不完整的。

缓存是否可以真正从内存中删除对象,即使其他地方仍有指向它的指针?如果是这样,我该怎么做呢?

更新

在进一步挖掘之后,我发现我们有一个相关的缓存项(索引),它在“主”缓存项之前到期时会导致问题。我重做了这个实体的缓存代码,将这两个结构存储在一起在一个Object数组中。这似乎解决了这个问题。

您没有足够的信息来解决问题。因此,我会查看答案,并勾选答案,以便最准确地解决给出的问题

4 个答案:

答案 0 :(得分:1)

缓存永远不会从内存中删除任何内容。

垃圾收集器从内存中删除对象,只有在没有对该对象的引用时才会发生这种情况。因此,只要您有对象的引用,即使它们从缓存中删除,也不会从内存中删除对象。

(缓存可以在请求中删除对象的引用。由于多个线程可以同时处理请求,因此可能会在不同的线程中发生某些事情,导致缓存丢弃项目。缓存不能等到所有线程都空闲丢弃项目,然后它可能永远无法做到这一点,你会耗尽内存。)

答案 1 :(得分:1)

是的,它会。如果为内存按下Web服务器,即使这样的代码也无法打印&#34; foo&#34;。

Context.Cache.Add(
            "someComplexObject",
            "foo",
            null,
            DateTime.Now.AddSeconds(seconds),
            System.Web.Caching.Cache.NoSlidingExpiration,
            System.Web.Caching.CacheItemPriority.NotRemovable,
            null
        );

Response.Write(Cache["someComplexObject").ToString());

你需要做一些聪明的事情,比如

string val = "foo";

Context.Cache.Add(
            "someComplexObject",
            val,
            null,
            DateTime.Now.AddSeconds(seconds),
            System.Web.Caching.Cache.NoSlidingExpiration,
            System.Web.Caching.CacheItemPriority.NotRemovable,
            null
        );

Response.Write(val.ToString());

此外,您需要在读取或写入缓存时锁定。您可以使用ReaderWriterLock(或类似)。这是为了避免在写入高速缓存时进行读取(并在读取高速缓存时写入)。

我已为SixPack library实施了几个缓存,您可能会觉得这些缓存很有趣,例如请参阅此CacheController类。

作为旁注,这个类比你需要的要复杂得多,因为它是允许你像这样缓存的系统的一部分:

[Cached]
public class MyTime : ContextBoundObject
{
        [CachedMethod(1)]
        public DateTime Get()
        {
                Console.WriteLine("Get invoked.");
                return DateTime.Now;
        }

        public DateTime GetNoCache()
        {
                Console.WriteLine("GetNoCache invoked.");
                return DateTime.Now;
        }
}

Full Example

NuGet package

答案 2 :(得分:0)

只要感觉如此,缓存就可以自由地删除对象。即它可以在您添加后立即检测内存压力并丢弃项目。

你真的不应该使用Cache传递对象。缓存是缓存 - 存储对象以便将来加速,但在单个请求期间使用其他方法传递对象。另请注意,与Items不同的是,共享缓存。

答案 3 :(得分:0)

是的,您的FillCache方法正在填充缓存,但是在此之间和检索缓存内容之间有时间。在这段时间内,您的缓存可能会失效。尝试从FillCache方法返回,以便始终拥有可靠的引用:

private SortedDictionary<Guid, Object> ComplexObjectCache()
{
    if (Context.Cache["someComplexObject"] == null)
    {
       var cacheItems = FillCache();
       return cacheItems;
    }
    return (SortedDictionary<Guid, Object>)Context.Cache["someComplexObject"];
}