我需要构建一个大的字符串列表并将其保存在内存中,但是在构建它时会抛出OutOfMemoryException。根据资源监视器,我仍然有1GB的内存可用。我发现this KB article解决了这个问题,但似乎它应该在框架1.1 SP1中修复(我使用的是3.5 sp1)。
有人能否了解幕后发生的事情? .net框架是否限制单个进程(在32位系统上)可以使用多少内存?如果是这样,我可以看到原因,但没有意义的是应用程序仅使用1.6GB,系统还剩下约1GB。
编辑 - 对于那些在这里提出更深入信息的人来说:
我有一个List(是的,我可以使用其他东西,但我现在只是原型。),我通过执行Guid.NewGuid()。ToString()生成一个随机字符串,并将其放入列表中。我想要做的是生成一个包含尽可能多的项目的列表,并测试查找特定项目的不同方法。我的第一个猜测是有些碎片正在进行,但除了下面的代码之外,我丢弃了所有碎片,但它仍然会发生。我不认为这个小片段会造成很多碎片,但我可能错了。
List<string> blah = new List<string>();
for (int i = 0; i < 50000000; i++)
{
blah.Add(Guid.NewGuid().ToString());
}
答案 0 :(得分:9)
问题可能不在于您没有“可用”内存,但更可能是您将内存碎片化得太多以至于当您尝试将项目添加到列表中时,必须调整其大小,没有一块可用内存可以容纳它。
这也会导致OutOfMemoryException。
列表有多大,换句话说,当你得到异常时,你有多少字符串,完全或粗略?
你如何填写清单?您是否事先知道要添加的项目数量?如果是这样,您在构建列表时是否指定了容量?
如果您不知道,是否可以解决这个问题,那么您可以指定容量吗?
答案 1 :(得分:9)
Win32对内存的每个进程限制为2GB。嗯,实际上是4GB,但是2GB是为内核模式保留的,除非你设置了/3GB操作系统启动选项。
答案 2 :(得分:2)
List&lt; T&gt;的默认构造函数以空数组作为内部存储开始。对Add(T item)的调用检查是否需要调整数组大小,并加倍 Capacity属性(通过EnsureCapacity方法)。当设置Capacity属性时......
因此,假设容量为n意味着在调整大小期间,您的总内存使用量为3n。
列表失败时包含多少项? 如果您知道将添加多少项,请尝试使用接受容量的构造函数。这可以避免任何可能需要完成的调整(如果需要大量内存块,可能会直接抛出OutOfMemoryException)。
答案 3 :(得分:1)
忘记碎片,LargeAddressAware或gcAllowVeryLargeObjects ...通过在我的控制台项目的“属性”页面的“构建”下取消选中“首选32位”复选框,我解决了这个问题。这是默认设置的......为什么?
答案 4 :(得分:0)
我真的不知道这个bug的细节,但多年前我确实碰到过这个或类似的东西。我们发现必不可少的是你的应用程序绑定的GDI句柄数量有一个硬限制。像9,999这样的东西。当您达到此限制时,无论有多少内存可用,应用程序都会因内存不足而崩溃。
所以你可能会做类似的事情,但既然你提到你正在使用字符串,我想你正在分割堆并超出其容量。如果你的字符串足够大,它们可能在大对象堆上。我认为在早期版本的框架中,LOH的实施非常糟糕。如果内存正确地为我服务,那么对象就不会被正确释放,这样就很容易只在LOH上耗尽空间。
有关更多信息,请参阅这些链接
http://www.simple-talk.com/dotnet/.net-framework/the-dangers-of-the-large-object-heap/ http://msdn.microsoft.com/en-us/magazine/cc534993.aspx http://blogs.msdn.com/maoni/archive/2006/04/18/large-object-heap.aspx http://social.msdn.microsoft.com/Forums/en-US/clr/thread/08e6bd5f-613e-41ae-9ab1-b05c7ff2710f