Comment .NET Framework alloue-t-il de la mémoire pour OutOfMemoryException?

144

En C ++, il est en fait possible de lever une exception par valeur sans allouer de mémoire sur un tas, donc cette situation a du sens. Mais dans .NET Framework OutOfMemoryExceptionest un type de référence, il est donc alloué sur un tas. Comment .NET Framework alloue-t-il de la mémoire OutOfMemoryExceptionlorsqu'il n'y a pas assez de mémoire pour créer un nouvel objet?

RX_DID_RX
la source
6
Excellente question. Peut-être que suffisamment de mémoire est réservée à cette situation.
GreatAndPowerfulOz
19
Juste pour ajouter aux autres réponses déjà ici, gardez à l'esprit que MOO signifie que le bloc que vous avez demandé ne peut pas être attribué. Si vous demandez 100 Mo et que le plus gros bloc disponible que le runtime peut trouver n'est que de 99 Mo, il échouera. Mais une exception MOO n'a besoin que de quelques octets de mémoire. Donc, ce n'est pas parce que votre allocation a échoué qu'il ne reste plus de mémoire. Mais bien sûr, il est probable que le runtime réserve de la mémoire pour se couvrir dans cette situation
Jason Williams
4
Votre hypothèse sur C ++ est incorrecte, au fait. Selon le compilateur, des exceptions peuvent bien être allouées sur le tas. Le compilateur MS ne le fait pas, mais dans l'ABI C ++ commun, des exceptions sont allouées sur le tas, sauf qu'il y a un petit tampon d'urgence préalloué qui sera utilisé à la place s'il n'y a plus d'espace sur le tas.
Sebastian Redl

Réponses:

163

Il est préalloué par le runtime. Si vous explorez le tas de tout processus géré, vous trouverez une instance de cette exception.

Voici les exceptions préallouées d'une application Hello World:

0:003> !dumpheap -stat -type Exception
Statistics:
      MT    Count    TotalSize Class Name
735f2920        1           84 System.ExecutionEngineException
735f28dc        1           84 System.StackOverflowException
735f2898        1           84 System.OutOfMemoryException
735f2744        1           84 System.Exception
735f2964        2          168 System.Threading.ThreadAbortException
Brian Rasmussen
la source
4
Mais le constructeur deOutOfMemoryException est appelé.
Tim Schmelter
36
Le runtime n'a pas à respecter les mêmes règles que votre code. Un autre exemple est que si vous lancez, StackOverflowExceptionvous pouvez l'attraper, mais si le moteur d'exécution lève cette exception, vous ne pouvez pas l'attraper (par défaut).
Brian Rasmussen
8
La plupart des mécanismes sous-jacents du CLR sont en fait écrits en "C" et "C ++". Ainsi, il est tout à fait possible que l'objet soit "remis en place" ou que la mémoire soit autrement manipulée.
GreatAndPowerfulOz
2
@hvd Quel est l'effet secondaire? OOM donne-t-il une trace de pile? J'aurais bien que le reste des informations soit assez statique?
James Barrass
7
Que faire si deux exceptions de celles du même type sont requises parce que deux threads les lancent en même temps?
Traubenfuchs
42

Lorsqu'une condition de mémoire insuffisante est rencontrée dans le runtime, il appelle ThrowOutOfMemory . Cela appelle Exception :: GetOOMException , qui construit l'objet sur la pile, puis le copie dans une instance globale allouée statiquement, qui est ensuite levée.

Ce n'est pas l'exception gérée, cependant, une exception C ++ déclaré dans ex.h . Les exceptions C ++ sont converties en exceptions gérées dans clrex.cpp , qui contient du code pour lancer spécifiquement l'exception OutOfMemoryException gérée préallouée, qui a été initialement allouée et construite dans appdomain.cpp .

Remarque: certains de ces fichiers sources sont volumineux et peuvent bloquer votre navigateur pendant plusieurs secondes pendant qu'il charge la coloration syntaxique.

Les sites d'appels que Tim Schmelter a liés dans un commentaire sur l'autre réponse ne sont pas liés au runtime manquant de mémoire et incapable de construire un objet.

Aléatoire832
la source