2013-05-22 3 views
4

Je dois générer de grosses images volumineuses, quelque chose comme 15000x3000. Je génère ces images avec GDI +, classe Bitmap.Récupérer la mémoire contiguë disponible

Bien sûr, de temps en temps, la génération échouera car il n'y a plus de mémoire pour instancier le bitmap. Mon but est d'informer mon utilisateur de la taille maximale de l'image qu'il est autorisé à générer.

Le message devrait ressembler à:

Vous avez essayé de générer une image de taille 15000x3000, mais il n'y a pas assez de mémoire. La taille maximale disponible est 10000x3000 ou 15000x1000.

L'idée de créer le message est quelque chose comme ça:

public bool CanCreateBitmap(Size size, out string message) 
{ 
    long availableMemory = this.GetAvailableContiguousMemory(); 
    long bytesRequiered = (long)size.Width * size.Height * 32; 

    if (availableMemory < bytesRequiered) 
    { 
     var sizeProposal1 = new Size(size.Width, (int)(availableMemory/(32 * size.Width))); 
     var sizeProposal2 = new Size((int)(availableMemory/(32 * size.Height)), size.Height); 

     message = string.Format("You tried to generate an image of size {0}, but there is not enough memory." 
       + Environment.NewLine + "The maximum size available is {1}, or {2}." 
       , size, sizeProposal1, sizeProposal2); 

     return false; 
    } 
    else 
    { 
     message = ""; 
     return true; 
    } 
} 

Mais je n'ai pas le code de la fonction GetAvailableContiguousMemory().

Existe-t-il une méthode pour récupérer la mémoire contigue dans .Net? Est-ce que je pose la bonne question pour atteindre mon objectif?

+0

Peut-être que vous pourriez mettre le code de création bitmap dans un bloc try/catch et gérer l'exception de mémoire insuffisante si cela se produit? – dandan78

+0

C'est déjà l'idée, mais le point principal ici est aussi de proposer quelque chose à l'utilisateur. Ils s'ennuient pour obtenir seulement un message "impossible de créer le bitmap" sans plus d'informations. –

Répondre

3

Il n'y a pas une telle fonction car la question "Combien de mémoire puis-je allouer" contient une condition de concurrence. Supposons qu'il existe une fonction dont vous avez besoin et que vous l'appeliez et qu'elle vous indique qu'il y a une énorme quantité de mémoire disponible. Vous communiquez cela à l'utilisateur, l'utilisateur décide de la taille de l'image et vous obtenez l'allocation de l'image. Mais d'autres processus ont pris la moitié de la mémoire disponible entre-temps et maintenant votre appel se brise avec OutOfMemoryException.

Il existe un problème similaire dans le streaming multimédia sur TCP/IP. Vous souhaitez commencer à diffuser une vidéo, mais cela nécessite beaucoup de bande passante réseau et vous voulez être sûr que cette bande passante sera disponible quelques minutes plus tard, car il serait contreproductif de démarrer le flux vidéo juste pour être coincé lorsque la lecture atteint les deux tiers de la longueur de la vidéo. Maintenant, ce problème a été résolu en réservant les ressources réseau pendant la phase de prise de contact - même si vous n'utilisez pas la bande passante en ce moment (le streaming vidéo n'a pas encore commencé).

Eh bien, vous pourriez essayer d'obtenir un effet similaire avec certains appels d'API Windows obscurs. Essayez de démarrer la recherche à partir de la fonction VirtualAlloc. Cependant, je ne vous recommande pas de suivre ce chemin parce que votre application, même si vous la faites fonctionner correctement, peut être instable ou non fiable ou affecter d'autres processus sur le système. En particulier, ces API Windows sont utilisées nativement en C++ et vous travaillez avec des tas gérés dans .NET - je n'ai pas essayé une telle approche et je ne peux pas prédire le résultat (mais j'aimerais avoir des nouvelles de vous si vous réussissez!).

Ce que vous demandez est une décision de conception. Je recommanderais également l'approche de dandan78 - laissez l'utilisateur sélectionner la taille de l'image, essayez de la créer et de communiquer l'erreur si la tentative a échoué. Les utilisateurs finiront par s'habituer aux capacités de leur ordinateur et ne pousseront pas le système au-delà de ses limites très souvent.

EDIT: Encore une chose à garder à l'esprit: il n'y a pas de "mémoire contiguë disponible". Le système d'exploitation vous prête des pages de mémoire virtuelle. Ces pages sont ensuite chargées en mémoire lorsqu'elles sont référencées. Si vous demandez beaucoup de mémoire, vous obtiendrez un tas de pages auxquelles des adresses consécutives seront attribuées dans l'espace de mémoire virtuelle et c'est ainsi que vous aurez l'impression que la mémoire est contiguë.Mais vous avez généralement des emplacements de mémoire non contigus renvoyés par l'instruction new car le gestionnaire de mémoire renvoie simplement le premier emplacement disponible sur le tas géré. Je sais que ces notes sont hors sujet pour cette question, mais il ne sera certainement pas douloureux de garder à l'esprit les stratégies de gestion de la mémoire dans des situations comme celle-ci.

+0

C'est vrai que la création pourrait échouer même si la fonction renvoie true. Mais j'ai déjà ajouté un try try pour créer l'instance. La fonction est ici juste pour ajouter un conseil pour l'utilisateur. –

+0

Je comprends ce dont vous avez besoin. Une dernière chose à garder à l'esprit: il n'y a pas de «mémoire contiguë disponible». Le système d'exploitation vous prête des pages de mémoire virtuelle. Ces pages sont ensuite chargées en mémoire lorsqu'elles sont référencées. Si vous demandez beaucoup de mémoire, vous obtiendrez un tas de pages auxquelles des adresses consécutives seront attribuées dans l'espace de mémoire virtuelle et c'est ainsi que vous aurez l'impression que la mémoire est contiguë. La seule façon d'avoir de la mémoire non contiguë est de recevoir des morceaux de mémoire des pages précédemment allouées, ce qui vous frappe lorsque vous allouez beaucoup de petits objets. –

+0

@sysexpand: votre commentaire sur la façon dont l'allocation fonctionne serait un bon ajout à votre réponse. –

3

Ce type de notification est un pansement qui n'aide pas réellement l'utilisateur. Ils voulaient vraiment créer cette grande image et une image arbitrairement plus petite n'était pas ce qu'ils voulaient. Si vous voulez faire cela de toute façon, vous devrez faire un pinping de VirtualQuery pour parcourir l'espace d'adressage virtuel et trouver des morceaux qui ne sont pas encore mappés.

Cela ne sert à rien d'avoir ce problème de nos jours, modifiez le paramètre Target Platform de votre projet à AnyCPU afin que votre programme puisse utiliser les gobs de l'espace mémoire virtuel disponible sur un système d'exploitation 64 bits.

Questions connexes