32

我正在测试.Net 中的集合有多大。从技术上讲,任何集合对象都可以增长到物理内存的大小。

然后我在一个服务器上测试了下面的代码,它有 16GB 内存,运行 Windows 2003 服务器和 Visual Studio 2008。我测试了 F# 和 C# 代码,并在运行时查看了任务管理器。我可以看到,在大约增长 2GB 内存后,程序因内存不足异常而崩溃。我确实在属性页中将目标平台设置为 x64。

open System.Collections.Generic

let d = new Dictionary<int, int>()

for i=1 to 1000000000 do
    d.Add(i,i)

我对C5集合库做了同样的测试。结果是 C5 中的字典可能会用完整个内存。代码使用 C5:

let d = C5.HashDictionary<int, int> ()
for i=1 to 1000000000 do
    d.Add(i,i)

有谁知道为什么?

4

4 回答 4

42

Microsoft CLR 有 2GB 的最大对象大小限制,即使是 64 位版本。(我不确定此限制是否也存在于其他实现中,例如 Mono。)

该限制适用于每个单独的对象——而不是所有对象的总大小——这意味着使用某种复合集合相对容易解决。

这里有一个讨论和一些示例代码......

似乎很少有官方文档提到这个限制。毕竟,它只是当前 CLR 的一个实现细节。我知道的唯一提及是在此页面上

在 64 位 Windows 操作系统上运行 64 位托管应用程序时,您可以创建不超过 2 GB 的对象。

于 2010-09-07T08:54:14.810 回答
22

在 4.5 之前的 .NET 版本中,最大对象大小为 2GB。从 4.5 开始,如果启用了 gcAllowVeryLargeObjects ,您可以分配更大的对象。请注意,限制string不受影响,但“数组”也应涵盖“列表”,因为列表由数组支持。

于 2012-06-26T06:49:18.960 回答
11

需要明确的是,字典使用单个数组来添加对。每次装满时它都会增长(加倍?)。当有 5.12 亿个对象时,其大小为 2GByte(使用 32 位对象指针,并假设完美分布)。再添加一个元素会使 Dictionary 再次尝试将数组大小加倍。繁荣。

C5 HashDictionary 使用线性哈希,并且可能使用一个桶数组,每个桶包含多个(16?)元素。它应该在以后(很多)遇到同样的问题。

于 2010-10-13T09:34:54.873 回答
1

“允许大对象”只会有助于摆脱 OOM 异常。

当需要存储很多对象时,您将看到的问题是 GC 停顿(暂停)。我们所做的是从 GC 中“隐藏”数据,这变成了一个非常实用的解决方案。

看到这个:https ://www.infoq.com/articles/Big-Memory-Part-3

您可以使用用作字典的缓存: https ://github.com/aumcode/nfx/tree/master/Source/NFX/ApplicationModel/Pile

见缓存部分

于 2017-07-15T22:45:38.470 回答