51 votes

MemoryCache Empty : Renvoie un message nul après avoir été défini.

J'ai un problème avec une application MVC 3 qui utilise le nouveau System.Runtime.Caching MemoryCache de .NET 4. J'ai remarqué qu'après un temps apparemment imprévisible, il arrête de mettre en cache des choses et agit comme s'il était vide. Considérez ce bout de code que j'ai pris directement d'une vue de test dans ASP.NET MVC :

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

Quand ça marche, comme on peut s'y attendre, "fred" est imprimé. Cependant, lorsque le problème commence à se poser, malgré la présence de Set() la valeur de MemoryCache.Default["myname"] est nulle. Je peux le prouver en plaçant un point d'arrêt sur la fonction Response.Write() et de définir et lire directement le cache en utilisant la fenêtre immédiate - Il ne le définit pas et reste nul ! La seule façon de le faire fonctionner à nouveau est de provoquer un recyclage de l'AppDomain.

Il est intéressant de noter que je peux provoquer le problème alors que l'application fonctionne normalement, en cassant le bouton Response.Write() la ligne et la course MemoryCache.Default.Dispose() . Après cela, MemoryCache.Default n'est pas lui-même nul (pourquoi ?), mais il n'enregistre rien de ce qu'il contient. Cela ne provoque pas d'erreur, mais n'enregistre rien du tout.

Quelqu'un peut-il le vérifier et l'expliquer ? Comme je crois l'avoir découvert, lorsque l'application cesse de fonctionner d'elle-même, quelque chose est en train de disposer MemoryCache.Default mais ce n'est pas moi !


UPDATE

Eh bien, j'en ai marre de ce problème maintenant ! CLRProfiler ne semble pas fonctionner avec MVC 3. L'outil CLR de SciTech était bon - tout comme RedGate ANTS. Mais tout ce qu'ils m'ont dit, c'est que l'objet MemoryCache est éliminé par quelque chose ! J'ai également prouvé (via une impression d'horodatage) qu'une PartialView de ma page qui devrait être mise en cache (spécifiée par OutputCacheAttribute) cesse d'être mise en cache après quelques minutes - elle commence à se rafraîchir à chaque appel de la page. Pour clarifier l'environnement, je fonctionne directement sur le serveur IIS 7.5 sur ma station de travail de développement fonctionnant sous Win 7 Ultimate. Les outils de mémoire mentionnés ci-dessus suggèrent que je n'utilise qu'environ 9 mb de mémoire en termes d'objets en jeu.

En désespoir de cause, j'ai modifié mon code de mise en cache pour qu'il recherche d'abord un HttpContext ambiant auquel s'accrocher et utilise sa fonctionnalité de mise en cache, si elle est disponible. Les premiers tests montrent que c'est fiable, mais cela ressemble à une mauvaise manipulation.

J'ai l'impression que MemoryCache et OutputCache ne sont pas justifiés pour fonctionner avec MVC 3...

68voto

Scott Hanselman Points 13109

Alors, voici quelques nouvelles. Nous avons étudié la question et OUI, il s'agit d'un bogue dans .NET 4.

La bonne nouvelle est que ce problème a été corrigé dans .NET 4.5. Si vous le pouvez, mettez votre installation à jour vers .NET 4.5 et vous serez tranquille.

L'autre bonne nouvelle est que ce correctif a été rétroporté vers .NET 4 et sera disponible en tant que QFE (Quick Fix...un correctif unique que vous appliquerez) #578315. Il a été rétroporté/corrigé il y a quelques jours et devrait être disponible dès que possible. Je vais essayer d'obtenir une date exacte, mais c'est pour bientôt.

L'autre bonne nouvelle est qu'il existe une solution de contournement pour .NET 4 avant le QFE. Cette solution est bizarre, mais elle pourrait vous débloquer.

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

J'espère que cela vous aidera.

MISE À JOUR : Le correctif est http://support.microsoft.com/kb/2828843 et vous pouvez le demander ici : https://support.microsoft.com/contactus/emailcontact.aspx?scid=sw;%5BLN%5D;1422

6voto

Dima Points 61

Nous avons le même problème. Je confirme qu'après un certain temps, le cache a été éliminé. Son champ privé _disposed est devenu 1. Je suis sûr que je n'ai pas d'appel à cache.Dispose dans mon code. Mais quand j'ai regardé le code de MemoryCache avec Reflector, j'ai vu que dans le constructeur, il souscrit à deux événements

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();
}

Ces deux gestionnaires d'événements font appel à Dispose. Il se peut qu'après le recyclage de certains domaines dans IIS, le domaine soit déchargé, mais le cache reste en mémoire (je ne suis pas sûr que ce soit possible).

3voto

Grant Points 2878

J'ai exactement les mêmes symptômes. J'ai finalement décidé d'utiliser la classe System.Web.Cache et de me connecter à HttpContext.Cache. Cela fonctionne parfaitement depuis 3 jours

2voto

AlexanderN Points 5805

Voir aussi ces liens relatifs au même problème.

MemoryCache est éliminé après PollingInterval lorsqu'il est utilisé dans une WebApp en mode Integrated Pipeline.

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

MemoryCache se met dans l'état Disposed par magie

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

1voto

TheCodeKing Points 11632

El MemoryCache évacuera automatiquement les éléments s'il atteint sa limite de mémoire. Cela pourrait se produire dans votre cas, avez-vous beaucoup d'éléments dans le cache ?

Vous pouvez contrôler les limites avec configuration . Par défaut, il optimise en fonction de la mémoire disponible.

Appeler certainement Dispose arrêtera le MemoryCache instance qui fonctionne car elle va nettoyer toutes les ressources non gérées prêtes à être éliminées. Vous ne devez appeler Dispose si vous n'avez pas l'intention d'utiliser le MemoryCache plus. Je ne pense pas que le problème soit nécessaire dans votre cas, à part lorsque vous l'appelez.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X