收集不同于 x86 的预期
本文关键字:x86 不同于 大容量 收集 | 更新日期: 2023-09-27 17:56:08
关于集合(如列表)中可以包含的最大项目数的主要问题。我在这里寻找答案,但我不明白原因。
假设我们正在处理一个 sizeof(int)
= 4 字节的List<int>
...每个人似乎都确信,对于x64,您最多可以拥有268,435,456 int
对于x86,最多可以拥有134,217,728 int
。链接:
- C# 中的列表大小限制
- C# 集合
的最大容量在哪里定义? - 列表
中的最大项目数是多少?
但是,当我自己测试时,我发现 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
的列表正好是 512MB 的内存......当您有 134217728 * sizeof(int) * 8 = 4,294,967,296 = 4GB...每个进程的限制超过 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
。
编辑2:我的计算错误:乘以 8 是错误的,确实是 MB =/= Mbits。我正在计算兆比特。仍然67108864整数只有 256MB...这比预期的要小得多。
List<T>
类的基础存储是T[]
数组。 数组的一个硬要求是进程必须能够分配一个连续的内存块来存储数组。
这是 32 位过程中的问题。 虚拟内存用于代码和数据,您可以从它们之间留下的孔中分配。 虽然 32 位进程将有 2 GB 的内存,但你永远不会接近接近这个大小的洞。 启动程序后,地址空间中最大的漏洞大约是 500 或 600 MB。 给予或接受,这在很大程度上取决于加载到进程中的 DLL。 不仅是框架程序集的 CLR、抖动和本机映像,还包括与托管代码无关的那种映像。 比如反恶意软件和大量"有用"的实用程序,它们会渗透到Dropbox和shell扩展等每个进程中。 一个基础差的人可以在两个小洞上切一个漂亮的大洞。
随着程序分配和释放内存一段时间,这些孔也会变小。 称为地址空间碎片的常见问题。 长时间运行的进程在 90 MB 分配时可能会失败,即使周围有大量未使用的内存也是如此。
您可以使用SysInternals的VMMap实用程序来获得更多见解。 Russinovich的书Windows Internals的副本通常也是必要的,以便理解你所看到的内容。
这可能也有帮助,但我能够通过使用提供的代码创建一个测试项目来复制这个67108864
限制
在控制台,Winform,WPF中,我能够获得134217728
限制
在 asp.net 我得到了33554432
限制
所以在你的一条评论中,你说[TestMethod]
,这似乎是问题所在。
虽然你可以拥有最大值项,但实际上在此之前你会耗尽内存。
以 x86运行,即使在 x46 盒子上,您也可以拥有的最大 RAM 将是 4GB,如果在 x86 版本的 Windows 上,则 2GB 或 3GB 是最大值。
可用的 ram 很可能要小得多,因为您只能为阵列分配最大的连续空间。