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:
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)
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:
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:
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.
User contributions licensed under CC BY-SA 3.0