捕获OutOfMemoryException如何工作?

Gam*_*ing 24 .net c# clr out-of-memory

我对OutOfMemoryException使用try/catch块捕获一个事实感到有些困惑.

给出以下代码:

Console.WriteLine("Starting");

for (int i = 0; i < 10; i++)
{
    try
    {
        OutOfMemory();
    }
    catch (Exception exception)
    {
        Console.WriteLine(exception.ToString());
    } 
}

try
{
    StackOverflow();
}
catch (Exception exception)
{
    Console.WriteLine(exception.ToString());
}

Console.WriteLine("Done");
Run Code Online (Sandbox Code Playgroud)

我用来创建OutOfMemory + StackOverflowException的方法:

public static void OutOfMemory()
{
    List<byte[]> data = new List<byte[]>(1500);

    while (true)
    {
        byte[] buffer = new byte[int.MaxValue / 2];

        for (int i = 0; i < buffer.Length; i++)
        {
            buffer[i] = 255;
        }

        data.Add(buffer);
    }
}

static void StackOverflow()
{
    StackOverflow();
}
Run Code Online (Sandbox Code Playgroud)

它打印出OutOfMemoryException10次​​,然后由于StackOverflowException它无法处理而终止.

RAM图在执行程序时看起来像这样: 图表显示内存被分配和释放10次

我现在的问题是为什么我们能够赶上OutOfMemoryException?在捕获它之后,我们可以继续执行我们想要的任何代码.正如RAM图所证明的,有内存释放.运行时如何知道GC可以使用哪些对象以及进一步执行哪些对象?

Guf*_*ffa 27

GC对程序中使用的引用进行分析,并且可以丢弃任何未在任何地方使用的对象.

一个OutOfMemoryException并不意味着内存完全耗尽,它只是意味着一个内存分配失败.如果你试图一次分配一个大的内存区域,可能仍然有足够的可用内存.

当没有足够的可用内存进行分配时,系统会进行垃圾回收以尝试释放内存.如果仍然没有足够的内存用于分配,它将抛出异常.

A StackOverflowException无法处理,因为它意味着堆栈已满,并且无法从堆中删除任何内容.您将需要更多的堆栈空间来继续运行将处理异常的代码,但没有更多.


Pau*_*hra 6

OutOfMemoryException很可能被抛出,因为你正在运行一个32位程序,你的内存图没有表明系统有多少ram,所以也许尝试将它构建为64位,并且可能使用MemoryFailPoint来防止这种情况发生.

您还可以让我们知道OutOfMemory()函数中的内容,以获得更清晰的图片.

PS StackOverFlow是唯一无法处理的错误.

编辑:如上所述,我认为它只是合乎逻辑的,因此之前没有提到它,如果你试图分配比你有'备用'更多的内存,那么就不可能这样做而且会发生异常.当您使用data.Add()分配大型数组时,它会在最终的"非法"添加发生之前崩溃,因此仍然有空闲内存.

所以我认为就是这时data.Add(缓冲区); 当您通过向"数据"添加400MB字节数组来触发2GB进程限制时,在构建数组期间会出现问题,例如,一个大约10亿个对象的数组,每个4字节,我预计大约400MB.

PS直到.net 4.5最大进程内存分配为2GB,之后有4.5个更大可用.