52

我对使用新的 .NET 4 System.Runtime.Caching MemoryCache 的 MVC 3 应用程序有疑问。我注意到,在看似不可预测的时间之后,它会停止缓存内容,并且表现得好像它是空的。考虑一下我直接从 ASP.NET MVC 中的测试视图中获取的这段代码:

MemoryCache.Default.Set("myname","fred", new CacheItemPolicy() { SlidingExpiration = new TimeSpan(0,5,0) });
Response.Write(MemoryCache.Default["myname"]);

当它工作时,可以预见的是“fred”会被打印出来。然而,当问题开始出现时,尽管Set(), 的值为MemoryCache.Default["myname"]null。我可以通过在行上设置断点并使用即时窗口直接设置和读取缓存来证明这一点Response.Write()- 它只是不会设置它并保持为空!让它再次工作的唯一方法是导致 AppDomain 回收。

有趣的是,当应用程序正常工作时,我可以通过断线Response.Write()并运行来引发问题MemoryCache.Default.Dispose()。之后, MemoryCache.Default 本身不是 null (为什么会这样?),但不会保存任何设置。它不会导致任何错误,但不会保存任何内容。

任何人都可以验证并解释吗?正如我相信我已经发现的那样,当应用程序停止自行运行时,有些东西正在处理MemoryCache.Default,但不是我!


更新

好吧,我现在厌倦了这个问题!CLRProfiler 似乎不适用于 MVC 3。SciTech 的 CLR 工具很好 - RedGate ANTS 也是如此。但是他们告诉我的只是 MemoryCache 对象正在被某些东西处理!我还证明(通过时间戳打印)我页面上应该缓存的 PartialView(由 OutputCacheAttribute 指定)在几分钟后停止缓存 - 每次调用页面时都会开始刷新。只是为了澄清环境,我直接在运行 Win 7 Ultimate 的开发工作站上的 IIS 7.5 服务器上运行。上面提到的内存工具表明我只使用了大约 9mb 的内存来播放对象。

绝望中,我将缓存代码更改为首先搜索环境 HttpContext 以连接并使用其缓存功能(如果可用)。早期的测试表明这是可靠的,但感觉就像一个讨厌的黑客。

我感觉 MemoryCache 和 OutputCache 不能与 MVC 3 一起使用...

4

5 回答 5

70

所以,这里有一些消息。我们对此进行了调查,是的,这是 .NET 4 中的一个错误。

好消息是它已在 .NET 4.5 中修复,因此如果可以,请将您的安装更新到 .NET 4.5,这样就可以了。

另一个好消息是,此修复已向后移植到 .NET 4,并将作为 QFE(快速修复...您将应用的一次性修复)#578315 提供。它在几天前被反向移植/修复,应该尽快出来。我会尽量得到一个确切的日期,但很快。

另一个好消息是在 QFE 之前的 .NET 4 上有一个解决方法。解决方法很奇怪,但它可以解除对您的阻止。

using (ExecutionContext.SuppressFlow())     {
          // Create memory cache instance under disabled execution context flow
         return new YourCacheThing.GeneralMemoryCache(…);
}

希望这可以帮助。

更新:修补程序是http://support.microsoft.com/kb/2828843,您可以在这里申请:https://support.microsoft.com/contactus/emailcontact.aspx?scid=sw;%5BLN%5D; 1422

于 2013-03-30T07:07:03.527 回答
6

我们有同样的问题。我确认在一段时间后缓存被处理掉了。它的私有字段 _disposed 变为 1。我确信我没有调用 cache.Dispose 在我的代码中。但是当我用 Reflector 查看 MemoryCache 的代码时,我看到,在构造函数中它订阅了两个事件

domain.DomainUnload += eventHandler;
domain.UnhandledException += exceptionEventHandler;

private void OnAppDomainUnload(object unusedObject, EventArgs unusedEventArgs)
{
  this.Dispose();
}

private void OnUnhandledException(object sender, UnhandledExceptionEventArgs eventArgs)
{
  if (!eventArgs.IsTerminating)
    return;
  this.Dispose();
}

这两个事件处理程序都调用了 Dispose。可能是在 IIS 中进行一些域回收之后,它会导致域卸载,但会将缓存保留在内存中(如果可能的话,我不同意)。

于 2013-03-04T14:15:43.997 回答
3

我一直在经历完全相同的症状。我终于改用 System.Web.Cache 类并连接到 HttpContext.Cache。在过去的 3 天里,它一直运行良好..

于 2012-11-21T21:38:13.980 回答
2

另请参阅与同一问题相关的这些链接。

在集成管道模式下的 WebApp 中使用时,MemoryCache 在 PollingInterval 之后被释放

http://connect.microsoft.com/VisualStudio/feedback/details/764911/memorycache-gets-disposed-after-pollinginterval-when-used-in-webapp-in-integrated-pipeline-mode

MemoryCache 神奇地进入 Disposed 状态

http://social.msdn.microsoft.com/Forums/en-US/netfxbcl/thread/1233ffb3-6480-431b-94ca-1190f96cf5f6

于 2013-03-22T03:17:34.653 回答
1

MemoryCache如果达到内存限制,它将自动驱逐项目。这可能发生在您的情况下,您的缓存中有很多项目吗?

您可以使用配置控制限制。默认情况下,它会根据可用内存进行优化。

当然调用Dispose会停止MemoryCache实例工作,因为它会清理所有准备好处理的非托管资源。Dispose仅当您不打算再使用时才应致电MemoryCache。我不认为这是你的情况的必要问题,除非你打电话给它。

于 2011-09-14T21:17:34.820 回答