W jaki sposób .NET Framework przydziela pamięć dla OutOfMemoryException?

144

W C ++ faktycznie można zgłosić wyjątek według wartości bez przydzielania pamięci na stercie, więc ta sytuacja ma sens. Ale w .NET Framework OutOfMemoryExceptionjest typem referencyjnym, dlatego jest przydzielany na stercie. W jaki sposób platforma .NET Framework przydziela pamięć, OutOfMemoryExceptiongdy jest za mało pamięci do utworzenia nowego obiektu?

RX_DID_RX
źródło
6
Świetne pytanie. Może wystarczająco dużo pamięci jest zarezerwowane tylko na tę sytuację.
GreatAndPowerfulOz
19
Aby dodać do innych odpowiedzi już tutaj, pamiętaj, że OOM oznacza, że ​​żądany blok nie może zostać przydzielony. Jeśli poprosisz o 100 MB, a największy dostępny blok, jaki może znaleźć środowisko wykonawcze, to tylko 99 MB, zakończy się niepowodzeniem. Ale wyjątek OOM potrzebuje tylko kilku bajtów pamięci. To, że alokacja się nie powiodła, nie oznacza, że ​​zostało zero pamięci. Ale oczywiście jest prawdopodobne, że środowisko wykonawcze rezerwuje trochę pamięci, aby pokryć się w tej sytuacji
Jason Williams
4
Nawiasem mówiąc, twoje założenie dotyczące C ++ jest błędne. W zależności od kompilatora wyjątki mogą być przydzielane na stercie. Kompilator MS tego nie robi, ale w Common C ++ ABI wyjątki są przydzielane na stercie, z wyjątkiem tego, że istnieje mały wstępnie przydzielony bufor awaryjny, który zostanie użyty zamiast tego, jeśli na stercie nie ma wolnego miejsca.
Sebastian Redl

Odpowiedzi:

163

Jest wstępnie przydzielany przez środowisko wykonawcze. Jeśli zbadasz stertę dowolnego zarządzanego procesu, znajdziesz wystąpienie tego wyjątku.

Oto wstępnie przydzielone wyjątki aplikacji 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
źródło
4
Ale konstruktorOutOfMemoryException nazywa się.
Tim Schmelter
36
Środowisko wykonawcze nie musi działać według tych samych reguł, co Twój kod. Innym przykładem jest to, że jeśli wyrzucisz StackOverflowException, możesz go złapać, ale jeśli środowisko wykonawcze zgłosi ten wyjątek, nie możesz go złapać (domyślnie).
Brian Rasmussen
8
Wiele z podstawowych mechanizmów CLR jest w rzeczywistości napisanych w językach „C” i „C ++”. Jest więc całkowicie możliwe, że obiekt jest „nowy na miejscu” lub w inny sposób manipuluje się pamięcią.
GreatAndPowerfulOz
2
@hvd Jaki jest efekt uboczny? Czy OOM daje ślad stosu? Chciałbym, żeby reszta informacji była dość statyczna?
James Barrass
7
Co jeśli dwa wyjątki tych o tym samym typie są wymagane, ponieważ dwa wątki rzucają je w tym samym czasie?
Traubenfuchs
42

Gdy w środowisku uruchomieniowym zostanie napotkany warunek braku pamięci, wywołuje ThrowOutOfMemory . To wywołuje Exception :: GetOOMException , który konstruuje obiekt na stosie, a następnie kopiuje go do statycznie przydzielonej instancji globalnej, która jest następnie generowana.

To nie jest zarządzany Wyjątek jednak, że jest to wyjątek C ++ zadeklarowane w ex.h . C ++ Wyjątki są konwertowane na zarządzanych wyjątków w clrex.cpp , który zawiera kod do specjalnie rzucać zdefiniowanej przez zarządzaną OutOfMemoryException, który został pierwotnie przydzieloną i skonstruowany w appdomain.cpp .

Uwaga: niektóre z tych plików źródłowych są duże i mogą zawiesić przeglądarkę na kilka sekund podczas ładowania podświetlania składni.

Witryny wywołań, które Tim Schmelter połączył w komentarzu do drugiej odpowiedzi, nie są związane z brakiem pamięci w środowisku wykonawczym i niemożnością skonstruowania obiektu.

Losowo 832
źródło