Collection <t>的最大容量与x86 </t>的预期不同

时间:2014-04-02 16:10:17

标签: c# .net

关于集合中可以包含的最大项目数的主要问题,例如List。我在这里寻找答案,但我不理解这个推理。

假设我们正在使用List<int> sizeof(int) = 4个字节...每个人似乎都确信对于x64,您最多可以有268,435,456 int和x86最大值134,217,728 int。链接:

但是,当我自己测试时,我发现x86的情况并非如此。谁能指出我可能出错的地方?

//// Test engine set to `x86` for `default processor architecture`
[TestMethod]
public void TestMemory()
{
    var x = new List<int>();

    try
    {
        for (long y = 0; y < long.MaxValue; y++)
        x.Add(0);
    }
    catch (Exception)
    {
        System.Diagnostics.Debug.WriteLine("Actual capacity (int): " + x.Count);
        System.Diagnostics.Debug.WriteLine("Size of objects: " + System.Runtime.InteropServices.Marshal.SizeOf(x.First().GetType())); //// This gives us "4"
    }
}

对于x64: 268435456 (预期)

对于x86: 67108864 (比预期少2倍)

为什么人们说包含134217728 int的List正好是512MB的内存...当你有134217728 * sizeof(int)* 8 = 4,294,967,296 = 4GB ...什么&#39;每个进程的限制超过2GB。 而67108864 * sizeof(int)* 8 = 2,147,483,648 = 2GB ......这是有道理的。

我在运行Windows 7 8GB RAM的64位计算机上使用.NET 4.5。在x64和x86中运行我的测试。

编辑:当我直接将容量设置为List<int>(134217728)时,我得到System.OutOfMemoryException

EDIT2 :我的计算错误:乘以8是错误的,实际上MB = / = Mbits。我在计算Mbits。仍然67108864英寸只有256MB ......这比预期的要小。

3 个答案:

答案 0 :(得分:8)

List<T>类的基础存储是T[]数组。对数组的一个硬性要求是该进程必须能够分配连续的内存块来存储数组。

这是32位进程中的问题。虚拟内存用于代码和数据,您可以从它们之间留下的漏洞进行分配。虽然一个32位进程将拥有2 GB的内存,但你永远不会到达接近该大小的一个洞。在您启动程序后,您可以获得的地址空间中最大的漏洞大约为500或600兆字节。给予或接受,这很大程度上取决于加载到进程中的DLL。不仅仅是CLR,框架程序集的抖动和本机映像,还有与托管代码无关的那种。就像反恶意软件和大量“有用”实用程序一样,它们会自动进入Dropbox和shell扩展等每个进程。一个基础不善的人可以用两个小洞来削减一个漂亮的大洞。

随着程序分配和释放内存一段时间,这些漏洞也会变小。一个称为地址空间碎片的常见问题。即使存在大量未使用的内存,长时间运行的进程也可能在90 MB的分配上失败。

您可以使用SysInternals'VMMap utility获取更多信息。 Russinovich的书籍Windows Internals的副本通常也是必要的,以便了解你所看到的内容。

答案 1 :(得分:1)

这可能也有帮助,但我能够通过使用提供的代码创建测试项目来复制此67108864限制

在console,winform,wpf中,我能够获得134217728限制

在asp.net中我得到33554432限制

所以你在评论中说[TestMethod],这似乎是个问题。

答案 2 :(得分:0)

虽然您可以拥有MaxValue项目,但实际上在此之前您将耗尽内存。

作为x86运行,即使在x46机器上,你可以拥有的最大内存也是4GB,如果在x86版本的Windows上,2GB或3GB是最大的。

可用的ram很可能小得多,因为你只能为阵列分配最大的连续空间。