我对我们能正好赶上一个事实有点糊涂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");
该方法我用来创建内存不足+ 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();
}
它打印出OutOfMemoryException
10次,然后因终止StackOverflowException
,它不能处理。
该RAM图形看起来就像是在执行程序:
我现在的问题是,为什么我们能够赶上OutOfMemoryException
? 捕获它之后,我们可以去上执行任何我们想要的代码。 它见证了RAM图形,有内存释放。 如何运行时知道哪些对象可以GC和它仍然需要进一步的执行力?
在GC上做了在程序中使用的参考文献进行分析,并能扔掉未在任何地方使用任何对象。
一个OutOfMemoryException
并不意味着内存完全耗尽,它只是意味着一个内存分配失败。 如果你想在一次分配大量的存储区域,仍可能存在大量的空闲内存留。
当没有足够的可用内存分配,系统做了垃圾收集,试图释放内存。 如果仍然没有足够的内存来分配,它会抛出异常。
一个StackOverflowException
无法处理,因为这意味着堆栈已满,并且它不可能从它删除任何东西,因为它是与堆。 你会需要更多的堆栈空间继续运行,将处理异常的代码,但没有更多。
该OutOfMemoryException异常很可能是抛出,因为你运行的是32位程序,你有没有指示的系统的RAM具有记忆图形,所以也许尝试建立它作为一个64位,也许使用MemoryFailPoint防止这种情况发生呢。
你也可以让我们知道什么是在一个更清晰的图片在内存不足()函数。
PS计算器是不能处理的唯一错误。
编辑:如上面提到的,而且我认为这只是合理的,因此并没有提到它,如果你例如尝试比你有“备用”,那么它是不可能这样做,发生异常分配更多的内存。 当你与你的data.Add分配大阵列()它落在了最后的“非法”添加发生之前,因此仍然有空闲内存。
所以,我认为它是在这一点上data.Add(缓冲); 当你加入一个400MB字节数组“数据”跳闸2GB进程限制的阵列,例如,在4个字节的一块,我认为那些是400MB左右约1十亿对象数组的建设过程中出现的问题。
PS直到.NET 4.5最大进程的内存分配是2GB,之后4.5大可用。
不知道这是否回答你的问题,但它如何决定哪些对象进行清理(简化)的解释是这样的:
垃圾收集器利用每一个正在运行的线程在你的程序,并标记所有顶级对象,这意味着从栈帧(即在其中执行目前的点由局部变量指出,所有的对象),以及所有可访问的所有对象通过静态字段指向的对象。
然后,它标志着一个新的水平的对象,这意味着由先前标记对象的所有字段所指向的所有对象。 重复此步骤,直到没有新的对象被标记。
因为C#不允许在正常情况下指针,一旦上一步完成后,它保证了非标对象是不被随后的代码提供服务,因此可以安全地清理。
在你的情况,如果你已经分配给压力增加了内存管理器中的对象没有被引用保持,这意味着GC将不得不清理它们的机会。 另外,请记住,OutOfMemoryException异常是指你的CLR程序的托管内存,而GC的工作原理有点那个“盒子”的外面。
你可以赶上一个OutOfMemoryException的原因是因为语言设计者决定让你。 究其原因,这是有时(但不是通常)实际是因为它在某些情况下可恢复的情况。
如果您尝试分配一个巨大的数组,你可能会得到一个OutOfMemoryException,但是对于庞大的阵列内存不会真正被分配 - 那么其他的代码仍然可以运行没有问题。 此外,由于堆栈展开的异常可能会导致前来其它对象符合垃圾收集,进一步增加可用内存量。
您的OutOfMemory()
方法创建数据结构( List<byte[]>
是本地的方法的范围内)。 当你的执行的线程是内部OutOfMemory
的方法,当前栈帧被认为是该列表中的GC根。 一旦你的线程在catch块结束,堆栈帧被弹出并被名单实际上已经成了无法访问。 因此,垃圾收集器决定了它可以安全地收集列表(它为你在你的记忆曲线图观察到)。