.NET框架如何为OutOfMemoryException分配内存?


144

在C ++中,实际上可以按值引发异常,而无需在堆上分配内存,因此这种情况很有意义。但是在.NET Framework OutOfMemoryException中,它是一种引用类型,因此它是在堆上分配的。OutOfMemoryException当没有足够的内存来创建新对象时,.NET Framework如何分配内存?


6
很好的问题。也许只为那种情况保留了足够的内存。
GreatAndPowerfulOz 2015年

19
只是要添加到此处已经存在的其他答案中,请记住,OOM意味着无法分配您请求的块。如果要求100Mb,并且运行时可以找到的最大可用块仅为99Mb,则它将失败。但是,OOM​​异常仅需要几个字节的内存。因此,仅仅因为分配失败并不意味着剩余的内存为零。但是,当然,它是可能的运行时储备一些内存覆盖自身在这种情况下
贾森-威廉姆斯

4
顺便说一下,您对C ++的假设是不正确的。根据编译器的不同,可以在堆上分配异常。MS编译器没有,但是在Common C ++ ABI中,例外是在堆上分配的,除非堆上没有剩余空间,否则将使用一个小的预分配的紧急缓冲区代替。
塞巴斯蒂安·雷德尔

Answers:


163

它由运行时预先分配。如果您浏览任何托管进程的堆,您将找到该异常的实例。

以下是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


36
运行时不必遵循与代码相同的规则。另一个示例是,如果StackOverflowException抛出该异常,则可以捕获它,但是如果运行时抛出该异常,则无法捕获(默认)。
布赖恩·拉斯穆森

8
实际上,CLR的许多基本机制实际上都是用“ C”和“ C ++”编写的。因此,完全有可能对象是“新的”或以其他方式操纵了内存。
GreatAndPowerfulOz

2
@hvd有什么副作用?OOM是否提供堆栈跟踪?我是否会其余所有信息都是静态的?
James Barrass

7
如果由于两个线程同时抛出它们而需要两个相同类型的异常怎么办?
Traubenfuchs,2015年

42

在运行时内部遇到内存不足的情况时,它将调用ThrowOutOfMemory。这将调用Exception :: GetOOMException,后者将对象构造在堆栈上,然后将其复制到静态分配的全局实例中,然后将其抛出。

但是,这不是托管异常,它是在ex.h中声明的C ++异常。C ++异常在clrex.cpp中转换为托管异常,其中包含专门抛出预分配的托管 OutOfMemoryException的代码,该托管异常最初是在appdomain.cpp中分配和构造的。

注意:其中一些源文件很大,并且在加载语法突出显示时可能会使您的浏览器挂起几秒钟。

Tim Schmelter在另一个答案的注释中链接的调用站点与运行时内存不足且无法构造对象无关。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.