C#:内存不足exception

今天我的应用程序抛出了一个OutOfMemoryException 。 对我来说,这是几乎不可能的,因为我有4GB的RAM和大量的虚拟内存。 当我尝试将现有集合添加到新列表时发生错误。

 List<Vehicle> vList = new List<Vehicle>(selectedVehicles); 

据我了解,这里分配的内存不多,因为我的新列表应该包含的车辆已经存在于内存中。 我不得不承认, Vehicle是一个非常复杂的课程,我试图一次将约50,000件物品添加到新列表中。 但是由于应用程序中的所有Vehicle都来自一个只有200MB大小的数据库:我不知道在这一点上可能会导致OutOfMemoryException

两点:

  1. 如果你正在运行一个32位的Windows,你将不会拥有所有的4GB容量,只有2GB。
  2. 不要忘记, List的底层实现是一个数组。 如果你的内存很分散,可能没有足够的连续空间来分配你的List ,尽pipe总共有很多可用内存。

3岁的话题,但我find了另一个工作的解决scheme。 如果您确定有足够的可用内存,运行64位操作系统并仍然收到exception,请确保在您的项目属性中设置此选项 在这里输入图像说明

.Net4.5对象不再有2GB的限制。 将此行添加到App.config

 <runtime> <gcAllowVeryLargeObjects enabled="true" /> </runtime> 

并且可以创build非常大的对象而不会出现OutOfMemoryException

请注意,它只能在x64操作系统上运行!

存储在数据库中的数据与应用程序中的内存相比是非常不同的。

没有办法得到你的对象的确切大小,但你可以这样做:

 GC.GetTotalMemory() 

在加载了一定数量的对象之后,在加载列表时查看内存的变化情况。

如果是导致内存使用过多的列表,那么我们可以考虑将其最小化的方法。 比如你为什么要把50,000个对象一次加载到内存中。 如果你需要他们,不是最好的调用数据库吗?

如果你看看这里: http : //www.dotnetperls.com/array-memory你也会看到,在.NET中的对象比他们的实际数据更大。 通用列表甚至比数组更多的是内存。 如果你的对象中有一个通用列表,那么它将会更快地增长。

OutOfMemoryException(在32位机器上)与内存中实际的硬性限制一样常常是关于碎片的 – 你会发现很多关于这个的,但这是我第一次简单地讨论它的谷歌命中: http : //blogs.msdn.com/b /joshwil/archive/2005/08/10/450202.aspx 。 (@Anthony Pegram在他的评论中提到了同样的问题)。

也就是说,上面的代码还有另外一种可能性:当您使用List的“IEnumerable”构造函数时,您可能不会向对象提供任何有关您传递的集合大小的提示到List构造函数。 如果传递的对象不是集合(不实现ICollection接口),那么List实现将需要增长几次(或多次),每次都会留下一个太小数组需要被垃圾收集。 垃圾收集器可能不会很快到达那些被丢弃的数组,你会得到你的错误。

最简单的解决方法是使用List(int capacity)构造函数来告诉框架什么支持数组大小分配(即使你估计和只是猜测“50000”例如),然后使用AddRange(IEnumerable collection)方法来实际填充你的列表。

所以,最简单的“修复”,如果我是对的:replace

 List<Vehicle> vList = new List<Vehicle>(selectedVehicles); 

 List<Vehicle> vList = new List<Vehicle>(50000); vList.AddRange(selectedVehicles); 

所有其他意见和答案仍然适用于整体devise决定 – 但这可能是一个快速解决scheme。

请注意(如下面的@Alex所述),如果selectedVehicles不是ICollection,则这只是一个问题。

你不应该试图一次把所有的列表,数据库中的元素的大小是不一样的,它所带入的内存。 如果你想处理的元素,你应该使用每个循环,并利用entity framework延迟加载,所以你不要把所有的元素一次进入内存。 如果你想显示列表使用分页(.Skip()和.take())

我的开发团队解决了这种情况:

我们将下面的构build后脚本添加到.exe项目中,并再次编译,将目标设置为x86并增加1.5 GB,同时还使用3.2 GB的x64平台目标增加内存。 我们的应用程序是32位。

相关url:

脚本:

 if exist "$(DevEnvDir)..\tools\vsvars32.bat" ( call "$(DevEnvDir)..\tools\vsvars32.bat" editbin /largeaddressaware "$(TargetPath)" )