今天我的申请今天投了一个OutOfMemoryException
.对我来说,这几乎是不可能的,因为我有4GB的RAM和大量的虚拟内存.当我尝试将现有集合添加到新列表时发生错误.
List<Vehicle> vList = new List<Vehicle>(selectedVehicles);
Run Code Online (Sandbox Code Playgroud)
根据我的理解,这里分配的内存不多,因为我的新列表应该包含的车辆已经存在于内存中.我不得不承认这Vehicle
是一个非常复杂的课程,我试图一次性将大约50.000个项目添加到新列表中.但是由于Vehicle
应用程序中的所有内容都来自一个只有200MB大小的数据库:我不知道OutOfMemoryException
在这一点上可能会导致什么.
Thr*_*ent 82
3岁的话题,但我找到了另一个有效的解决方案.如果您确定有足够的可用内存,运行64位操作系统并仍然获得异常,请务必在项目属性中设置此选项
Tud*_*dor 73
两点:
List
是一个数组.如果您的内存严重碎片化,可能没有足够的连续空间来分配您List
的内存,即使总共有足够的可用内存.小智 67
.Net4.5对象不再有2GB的限制.将此行添加到App.config
<runtime>
<gcAllowVeryLargeObjects enabled="true" />
</runtime>
Run Code Online (Sandbox Code Playgroud)
并且可以在不获取OutOfMemoryException的情况下创建非常大的对象
请注意它只适用于x64操作系统!
Ada*_*ley 14
与应用程序中的内存相比,存储在数据库中的数据非常不同
没有办法获得对象的确切大小,但您可以这样做:
GC.GetTotalMemory()
Run Code Online (Sandbox Code Playgroud)
加载了一定数量的对象后,在加载列表时查看内存的更改量.
如果它是导致过多内存使用的列表,那么我们可以查看最小化它的方法.例如,为什么要首先将50,000个对象一次性加载到内存中.根据需要调用数据库不是最好的吗?
如果你看一下这里:http://www.dotnetperls.com/array-memory你还会看到.NET中的对象大于它们的实际数据.通用列表甚至比数组更重要.如果您的对象中有一个通用列表,那么它将变得更快.
OutOfMemoryException(在32位机器上)与碎片化一样经常与内存的实际硬限制一样 - 你会发现很多关于这一点,但这是我的第一篇google热门话题,简要讨论它: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)
方法实际填充列表.
所以,最简单的"修复",如果我是对的:替换
List<Vehicle> vList = new List<Vehicle>(selectedVehicles);
Run Code Online (Sandbox Code Playgroud)
同
List<Vehicle> vList = new List<Vehicle>(50000);
vList.AddRange(selectedVehicles);
Run Code Online (Sandbox Code Playgroud)
所有其他评论和答案仍然适用于整体设计决策 - 但这可能是一个快速解决方案.
注意(如下面的@Alex评论),如果selectedVehicles
不是ICollection ,这只是一个问题.
我知道这是一个老问题,但由于没有一个答案提到大对象堆,这可能对发现这个问题的其他人有用......
.NET 中超过 85,000 字节的任何内存分配都来自大对象堆 (LOH),而不是普通的小对象堆。为什么这很重要?因为大对象堆没有被压缩。这意味着大型对象堆会变得碎片化,根据我的经验,这不可避免地会导致内存不足错误。
在最初的问题中,列表中有 50,000 个项目。列表内部使用数组,假设 32 位需要 50,000 x 4 字节 = 200,000 字节(如果是 64 位,则需要两倍)。因此内存分配来自大对象堆。
所以你对此能做些什么?
如果您使用的是 4.5.1 之前的 .net 版本,那么您所能做的就是意识到该问题并尝试避免它。因此,在这种情况下,您可以拥有一个车辆列表列表,而不是一个车辆列表,前提是列表中的元素不超过 18,000 个。这可能会导致一些丑陋的代码,但这是可行的解决方法。
如果您使用 .net 4.5.1 或更高版本,则垃圾收集器的行为会发生微妙的变化。如果您在要进行大量内存分配的位置添加以下行:
System.Runtime.GCSettings.LargeObjectHeapCompactionMode = System.Runtime.GCLargeObjectHeapCompactionMode.CompactOnce;
Run Code Online (Sandbox Code Playgroud)
它将强制垃圾收集器压缩大对象堆 - 仅限下一次。
这可能不是最好的解决方案,但以下内容对我有用:
int tries = 0;
while (tries++ < 2)
{
try
{
. . some large allocation . .
return;
}
catch (System.OutOfMemoryException)
{
System.Runtime.GCSettings.LargeObjectHeapCompactionMode = System.Runtime.GCLargeObjectHeapCompactionMode.CompactOnce;
GC.Collect();
}
}
Run Code Online (Sandbox Code Playgroud)
当然,这仅在您有可用的物理(或虚拟)内存时才有帮助。
小智 5
我的开发团队解决了这种情况:
我们将以下构建后脚本添加到.exe项目中,然后再次编译,将目标设置为x86并增加1.5 gb,并且将x64 Platform目标使用3.2 gb增加内存。我们的应用程序是32位。
相关网址:
脚本:
if exist "$(DevEnvDir)..\tools\vsvars32.bat" (
call "$(DevEnvDir)..\tools\vsvars32.bat"
editbin /largeaddressaware "$(TargetPath)"
)
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
182874 次 |
最近记录: |