简体   繁体   中英

Difference between actual OOM and 2GB object OOM?

I was wondering if there is some difference between the OOM exceptions thrown for an actual OOM (memory runs out), and the exception thrown when the 2GB object limit is hit ?

I have the following code for causing the OOMs (no app.config changes, gcAllowVeryLargeObjects is by default set to false ):

struct Data
{
    double a;
    double b;
}

// Causes OOM due to the 2GB object limit.
List<Data> a = new List<Data>(134217725);

// Causes OOM due to actual OOM.
List<Data[]> b = new List<Data[]>();
for (int i = 0; i < 13421772; i++)
{
    b.Add(new Data[134217724]);
}

Now, I've executed the code from Visual Studio, and I get the following exceptions:

  • 2GB object limit
System.OutOfMemoryException
  HResult=0x8007000E
  Message=Exception of type 'System.OutOfMemoryException' was thrown.
  Source=mscorlib
  StackTrace:
   at System.Collections.Generic.List`1..ctor(Int32 capacity) 
   at ConsoleApp1.Program.Main(String[] args)
  • actual OOM
System.OutOfMemoryException
  HResult=0x8007000E
  Message=Exception of type 'System.OutOfMemoryException' was thrown.
  Source=ConsoleApp1
  StackTrace:
   at ConsoleApp1.Program.Main(String[] args)

From here, it doesn't seem like there is a significant difference between the two exceptions (other than the stack trace/source).

On the other hand, I executed the exact same thing from LINQPad and got the following:

  • 2GB limit

LINQPad 2GB 限制异常

  • actual OOM

LINQPad 实际 OOM 异常

Executing RuntimeInformation.FrameworkDescription from both places results in .NET Framework 4.8.4341.0

My question is about detecting/differentiating between the two cases, although I am also curious as to why the error messages differ between the LINQPad and VS executions.

I can explain the difference between LinqPad and Visual Studio:

If you run x86 DEBUG and RELEASE .Net Framework 4.8 builds of the following code:

static void Main()
{
    try
    {
        List<Data> a = new List<Data>(134217725);
    }
    
    catch (Exception e)
    {
        Console.WriteLine(e.Message);
    }

    try
    {
        List<Data[]> b = new List<Data[]>();

        for (int i = 0; i < 13421772; i++)
        {
            b.Add(new Data[134217724]);
        }
    }

    catch (Exception e)
    {
        Console.WriteLine(e.Message);
    }
}

For the RELEASE build you get:

Array dimensions exceeded supported range.
Exception of type 'System.OutOfMemoryException' was thrown.

For the DEBUG build you get:

Exception of type 'System.OutOfMemoryException' was thrown.
Exception of type 'System.OutOfMemoryException' was thrown.

This implies that the LINQPAD version is RELEASE and the Visual Studio version is DEBUG .

So the answer is: Yes, there clearly is some difference, but:

  • Only the message differs
  • We should not rely on this never changing
  • It differs between DEBUG and RELEASE builds.

Aside:

On my PC, the DEBUG build of the test code above immediately throws the two OutOfMemoryException exceptions.

However, the RELEASE build quickly throws the first OutOfMemoryException , but it is several seconds before it throws the second exception. During this time, its memory usage increases (according to Task Manager ).

So clearly there is some other difference under the hood, at least for.Net Framework 4.8. I haven't tried this with.Net 5 or.Net Core.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM