36 votes

Quand est-il OK pour attraper une exception OutOfMemoryException et comment le gérer?

Hier, j'ai pris part à une discussion sur AINSI consacré à OutOfMemoryException et les avantages et les inconvénients de le manipuler (C# try {} catch {}).

Mon pros de la manipulation ont été:

  • Le fait que OutOfMemoryException a été jeté n'a généralement pas de dire que l'état d'un programme a été endommagé;
  • Selon la documentation "de la suite Microsoft intermediate (MSIL) instructions de jeter OutOfMemoryException: boîte, newarr, newobj" qui vient de (généralement) signifie que le CLR a tenté de trouver un bloc de mémoire d'une taille donnée et a été incapable de le faire; il n'est pas de dire que pas un seul octet de gauche à notre disposition;

Mais pas tous les gens ont été d'accord et a spéculé sur programme inconnue de l'état après cette exception et une incapacité à faire quelque chose d'utile, car il faudra encore plus de mémoire.

Donc, ma question est: quelles sont les raisons sérieuses de ne pas manipuler OutOfMemoryException et lui donner immédiatement lorsqu'il se produit?

Modifié: pensez-vous que OOME est aussi mortelles que ExecutionEngineException?

35voto

Marc Gravell Points 482669

OMI, puisque vous ne pouvez pas prédire ce que vous pouvez/ne pouvez pas le faire après un OOM (donc vous ne pouvez pas fiable du processus de l'erreur), ou ce que d'autre n'a/n'a pas eu lieu lors de dérouler la pile à l'endroit où vous êtes (donc la BCL n'a pas traitées de manière fiable l'erreur), votre application doit maintenant être supposé être dans un état corrompu. Si vous "réparer" votre code par la manipulation de cette exception vous enterrer votre tête dans le sable.

J'ai peut-être tort ici, mais pour moi, ce message dit un GROS problème. La bonne solution est de comprendre pourquoi vous avez chomped si la mémoire, et à l'adresse (par exemple, vous avez une fuite? pourriez-vous passer à un streaming API?). Même la commutation de l'x64 n'est pas une balle magique ici; les tableaux (et donc des listes) sont encore de taille limitée, et de l'augmentation de la taille de référence signifie que vous pouvez résoudre numériquement moins de références dans les 2 go de l'objet de la pac.

Si vous avez besoin de chance de traitement de certaines données, et sont heureux pour elle à l'échec: le lancement d'un second processus (un AppDomain n'est pas assez bon). Si il explose, détruire le processus. Problème résolu, et l'original de votre processus/AppDomain est sûr.

21voto

Matthew Whited Points 12255

Nous avons tous d'écrire des applications différentes. Dans un WinForms ou ASP.Net app je serais probablement juste de journal de l'exception, de notifier à l'utilisateur, essayez d'enregistrer l'état, et de l'arrêt/redémarrage. Mais comme Igor mentionné dans les commentaires cela pourrait très bien être de construire une certaine forme d'application d'édition d'image et le processus de chargement de la 100e 20 MO d'image RAW pourrait pousser l'application sur le bord. Voulez-vous vraiment l'utilisation de perdre la totalité de leur travail à partir de quelque chose d'aussi simple que de dire. "Désolé, impossible de charger des images de plus en ce moment".

Un autre exemple qu'il pourrait être utile pour attraper hors de la mémoire exceptions est en fin de traitement par lots. Vous pourriez avoir un modèle standard de chargement multi-mega-octets de fichiers en mémoire pour le traitement, mais un jour, à l'improviste un multi-giga-octets de fichiers est chargé. Lorsque la capacité de mémoire se produit, vous pourriez journal le message à un utilisateur de notification de la file d'attente, puis passer au fichier suivant.

Oui, il est possible que quelque chose d'autre pourrait faire sauter en même temps, mais ceux qui sont trop serait connecté et informé si possible. Si, enfin, la GC est pas en mesure de traiter plus de mémoire que l'application va aller vers le bas dur de toute façon. (Le GC s'exécute dans un fil non protégés.)

Ne pas oublier que nous développons tous types de demandes. Et si vous êtes sur de l'ancien, sous la contrainte des machines, vous n'aurez probablement jamais obtenir une OutOfMemoryException pour les applications d'entreprise... mais encore une fois nous ne sommes pas tous outil de business développeurs.

Pour modifier votre...

De mémoire peut être causée par une mémoire non managée la fragmentation et l'épinglage. Il peut également être provoquée par l'afflux de demandes d'allocation. Si nous devions mettre en place un drapeau blanc et de tracer une ligne dans le sable sur ces questions simples, rien n'aurait pu se faire dans les grandes données de projets de transformation. Maintenant, comparons un fatal exception de Moteur, il n'y a rien que vous pouvez faire à la point de l'exécution des chutes de mort en vertu de votre code. J'espère que vous êtes en mesure de se connecter (mais probablement pas) pourquoi votre code est tombé sur son visage de sorte que vous pouvez les éviter dans le futur. Mais, plus important encore, nous espérons que votre code est écrit dans une manière qui pourrait permettre de sécuriser la récupération de données autant que vous le pouvez. Peut-être même récupérer le dernier bon de le préciser dans votre demande et, éventuellement, sautez la délinquance des données corrompues et lui permettre d'être traitées manuellement et récupéré.

Pourtant, dans le même temps, il est tout aussi possible de disposer de données de la corruption causée par l'injection SQL, out-of-sync versions de logiciel, de manipulation du pointeur, tampon, des dépassements, et de nombreux autres problèmes. Éviter une question juste parce que vous pensez que vous ne pouvez pas récupérer à partir, il est un excellent moyen de donner aux utilisateurs les messages d'erreur comme constructive , Veuillez contacter votre administrateur système.

18voto

Christian.K Points 18883

Certains intervenants ont noté qu'il existe des situations, lorsque OOM pourrait être le résultat immédiat de la tentative d'allouer un grand nombre d'octets (application graphique, l'allocation de large, etc.). À noter que pour cette fin, vous pouvez utiliser le MemoryFailPoint classe, ce qui pose un InsufficientMemoryException (lui-même dérivé de OutOfMemoryException). Qui peut être pris en toute sécurité, car il est soulevé avant la réelle tentative d'allouer de la mémoire a été faite. Cependant, cela ne peut vraiment réduire la likelyness d'un OOM, jamais l'empêcher.

13voto

ChrisF Points 74295

Tout dépend de la situation.

Tout à fait il ya quelques années maintenant, je travaille sur un temps réel moteur de rendu 3D. Au moment où nous avons chargé toute la géométrie pour le modèle en mémoire au démarrage, mais uniquement chargé de la texture des images quand nous avons eu besoin de les afficher. Cela signifiait quand vint le jour, nos clients ont de chargement énorme (2 GO), des modèles, nous avons été en mesure de faire face. La géométrie occupé moins de 2 GO, mais quand toutes les textures ont été ajoutées il serait > 2 GO. Par piégeage de l'erreur de mémoire qui a été soulevé lorsque nous avons essayé de charger la texture, nous avons pu réaliser sur l'affichage du modèle, mais juste comme la plaine de la géométrie.

Nous avons encore eu un problème si la géométrie a été de plus de 2 GO, mais c'était une autre histoire.

Évidemment, si vous obtenez une erreur de mémoire insuffisante avec quelque chose de fondamental à votre application, puis vous avez pas d'autre choix que d'arrêter - mais le faire avec autant de tact que vous le pouvez.

10voto

Sergey Teplyakov Points 6556

Suggérer Christopher Brumme commentaire dans le "Cadre de lignes Directrices de Conception" p.238 (7.3.7 OutOfMemoryException):

À une extrémité du spectre, une OutOfMemoryException pourrait être le résultat d'un échec à obtenir 12 octets pour implicitement l'autoboxing, ou l'échec de l'JIT code qui est nécessaire pour les rejeter. Ces cas sont des cas de défaillances catastrophiques et, dans l'idéal, entraîner la résiliation du processus. À l'autre extrémité du spectre, une OutOfMemoryException pourrait être le résultat d'un thread pour demander un 1 GO de tableau d'octets. Le fait que nous n'avons pas cette allocation tentative n'a pas d'impact sur la cohérence et la viabilité du reste du processus.

La triste réalité est que la liste de révocation de certificats 2.0 ne fait pas de distinction entre les points sur ce spectre. Dans la plupart des processus gérés, tous les OutOfMemoryExceptions sont considérés comme équivalents et qu'ils aboutissent à une exception gérée propagé le fil. Cependant, vous ne pouvez pas dépendre de votre sauvegarde l'exécution d'un code, parce que nous ne parviennent pas à JIT certains de vos rejeter les méthodes, ou nous pourrions ne pas s'exécuter constructeurs statiques nécessaires pour la sauvegarde.

Aussi, gardez à l'esprit que toutes les autres exceptions peuvent s'inscrire dans une OutOfMemoryException si il n'y a pas assez de mémoire pour instancier ces autres objets d'exception. Aussi, nous allons vous donner une unique exception OutOfMemoryException avec sa propre trace de la pile si nous le pouvons. Mais si nous sommes assez serré sur la mémoire, vous partagerez un inintéressant instance globale avec tout le monde dans le processus.

Ma meilleure recommandation est que vous devez traiter OutOfMemoryException comme toute autre application de l'exception. Vous faites votre meilleure tentative à manipuler et ramain cohérente. Dans le futur, j'espère que le CLR peut faire un meilleur travail de distinguer catastrophique OOM de l'1 GO de tableau d'octets cas. Si oui, il est susceptible de provoquer l'arrêt du processus de la catastrophe cas, de quitter l'application pour traiter la moins risquée ceux. Par dangereux tous OOM cas comme la moins risquée ceux, vous vous préparez pour la journée.

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