【发布时间】:2021-03-05 13:33:04
【问题描述】:
我想知道实际OOM(内存耗尽)引发的OOM异常与2GB object limit is hit时引发的异常之间是否存在差异?
我有以下导致 OOM 的代码(没有 app.config 更改,gcAllowVeryLargeObjects 默认设置为 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]);
}
现在,我已从 Visual Studio 执行代码,但出现以下异常:
- 2GB 对象限制
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)
- 实际OOM
System.OutOfMemoryException
HResult=0x8007000E
Message=Exception of type 'System.OutOfMemoryException' was thrown.
Source=ConsoleApp1
StackTrace:
at ConsoleApp1.Program.Main(String[] args)
从这里看来,这两个异常(堆栈跟踪/源除外)之间似乎没有显着差异。
另一方面,我从 LINQPad 执行了完全相同的操作并得到以下结果:
- 2GB 限制
- 实际OOM
从两个地方执行RuntimeInformation.FrameworkDescription 会导致.NET Framework 4.8.4341.0
我的问题是关于检测/区分这两种情况,尽管我也很好奇为什么 LINQPad 和 VS 执行之间的错误消息不同。
【问题讨论】:
-
除了学术好奇心之外,您对这个问题有什么目的吗?您使用 VisualStudio 和 linqPad 的目标是什么版本的 .net?
-
@JonasH .net 版本都是
.NET Framework 4.8.4341.0。我想知道是否可以以某种方式检测到不同的情况,因为它们代表不同的状态:一个无法帮助(实际 OOM)并提出应用程序设计问题,而另一个(2GB 大小限制)可以通过不同的方式解决处理单个数据结构(如果可以检测到异常之间的差异,甚至可能在运行时)。 -
您可以捕获 OOM 并尝试按照您的建议(或我的理解)再次分块分配。然后它会再次因 OOM 失败或工作。
-
如果您正在运行 32 位代码,您可能还需要担心大对象堆碎片。因此,有可能分配两个 0.5Gb 块,其中 1Gb 块失败。如果您需要处理对象,只需启用
gcAllowVeryLargeObjects似乎更合理。也就是说,我希望异常包括它尝试分配的内存量,因为这在调查异常时很有用。
标签: c# exception out-of-memory