2013-06-15 3 views
1

J'ai une application qui enregistre/met en cache de nombreux objets dans un champ statique. Lorsque de nombreux objets sont enregistrés pendant la durée de vie de l'application, une exception de mémoire insuffisante est générée car le cache devient trop volumineux.Indicateur de pression de mémoire/compteur/statistiques

Y a-t-il une classe ou un objet qui m'informe que la mémoire est épuisée et qu'il y aura un outofmemoryexception bientôt pour que je sache que j'ai besoin de libérer de la mémoire en supprimant certains de ces objets en cache? Je suis à la recherche d'un signe indiquant qu'il y a une pression mémoire dans l'application afin que je puisse prendre des mesures de précaution pendant l'exécution de l'application avant que l'exception de mémoire soit levée.

+0

cochez cette réponse: http://stackoverflow.com/a/1248141/941243 – Chris

Répondre

0

J'ai aussi une application qui utilise autant de RAM que possible. Vous avez quelques options ici en fonction de votre scénario spécifique (tous ont des inconvénients). L'un des plus simples est de préallouer un tampon circulaire de classes (ou octets) que vous mettez en cache pour consommer tout le RAM vers l'avant. Ce n'est généralement pas préférable parce que consommer toute la RAM sur une boîte lorsque vous n'en avez pas besoin est tout simplement grossier.

Une autre façon de gérer les caches volumineux (ou d'éviter les exceptions de mémoire insuffisante) est de vérifier d'abord que la mémoire dont j'ai besoin existe avant l'allocation. Cela a l'inconvénient de devoir sérialiser les allocations de mémoire. Sinon, le temps entre la vérification de la RAM disponible et l'allocation que vous pouvez manquer de RAM.

Voici un échantillon de la meilleure façon que j'ai trouvé de le faire dans .NET:

//Wait for enough memory 
var temp = new System.Diagnostics.PerformanceCounter("Memory", "Available MBytes"); 
long freeMemory = Convert.ToInt64(temp.NextValue()) * (long)1000000; 
long neededMemory = (long)bytesToAllocate; 
int attempts=1200; //two minutes 

while (freeMemory < neededMemory) 
{ 
    //Signal that memory needs to be freed 
    Console.WriteLine("Waiting for enough free memory:. Free Memory:" + freeMemory + " Needed Memory(MB):" + neededMemory); 
    System.Threading.Thread.Sleep(100); 
    freeMemory = Convert.ToInt64(temp.NextValue()) * (long)1000000; 
    --attempts; 

    if (0 == attempts) 
      throw new OutOfMemoryException("Could not get enough free memory. File:" + Path.GetFileName(wavFileURL)); 
} 

//Try and allocate the memory we need. 

De plus, une fois que je suis à l'intérieur de la boucle while je signale que de la mémoire doit être libéré (en fonction de votre application). Remarque: j'ai essayé de simplifier le code en utilisant une instruction Sleep, mais finalement vous voudriez un certain type d'opération non-polling si possible. Je ne suis pas sûr sur les spécificités de votre application, mais si vous êtes multithread, ou exécutez plusieurs exécutables différents, il peut être préférable de sérialiser cette vérification de la mémoire lorsque la mémoire allouée à la mémoire cache. Si c'est le cas, j'utilise un sémaphore pour m'assurer qu'un seul thread et/ou processus peut allouer de la RAM si nécessaire. Semblable à ceci:

Semaphore namedSemaphore = new Semaphore(1, 1, "MemoryAllocationSemaphore"); //named semaphores are cross process 
    if (bytesToAllocate > 2000000) //if we need less than 2MB then dont bother locking. 
    { 
      if (!namedSemaphore.WaitOne((int)TimeSpan.FromMinutes(15).TotalMilliseconds)) 
      { 
       throw new TimeoutException("Waited over 15 minutes for aquiring memory allocation semaphore"); 
      } 
    } 

Puis un peu plus tard cette appel:

namedSemaphore.Release(); 

dans un bloc finally pour libérer le sémaphores.

Une autre option consiste à utiliser un verrou d'écriture unique à plusieurs lecteurs.Pour avoir plusieurs threads tirant des données du cache (comme la classe ReaderWriterLock). Cela a l'avantage que, pendant que vous écrivez, vous pouvez vérifier la pression et le nettoyage de la mémoire, puis ajouter davantage au cache, tout en conservant plusieurs threads traitant les données. L'inconvénient est bien sûr que le goulot d'étranglement de l'obtention de données dans le cache provient d'un seul point fixe.

0

Si vous avez tellement de données en cache que vous manquez de mémoire, cela indique que quelque chose ne va vraiment pas avec votre approche de mise en cache. Même en tant que processus 32 bits, vous disposez d'un espace d'adressage de 2 Go.

Vous devez envisager d'utiliser un cache limité dans lequel l'utilisateur peut définir une taille de cache préférée et supprimer automatiquement les objets lorsque cette taille est atteinte. Vous pouvez implémenter certaines stratégies de mise en cache pour sélectionner les objets à retirer du cache: les objets les plus anciens ou les objets les moins fréquemment utilisés ou une combinaison de ceux-ci.

Vous pouvez également essayer de mapper une partie de votre cache sur le disque et conserver uniquement les objets les plus fréquemment utilisés en mémoire. Lorsqu'un objet dont vous avez besoin n'est pas en mémoire, vous pouvez le désérialiser à partir du disque et le remettre en mémoire. Si un objet n'est pas utilisé pendant un certain temps, vous pouvez l'échanger sur le disque.