【问题标题】:Error when Dictionary count is bigger as 89478457字典计数大于 89478457 时出错
【发布时间】:2023-03-12 12:15:01
【问题描述】:

我正在执行此命令

Dictionary<UInt64, int> myIntDict = new Dictionary<UInt64, int>(89478458);

这个错误:

System.OutOfMemoryException was unhandled  HResult=-2147024882
Message=Array dimensions exceeded supported range.
Source=mscorlib
StackTrace:
   at System.Collections.Generic.Dictionary`2.Initialize(Int32 capacity)
   at System.Collections.Generic.Dictionary`2..ctor(Int32 capacity, IEqualityComparer`1 comparer)

在 89478457 上没有错误。这里是Dictionary.cs中Initialize的来源:

    private void Initialize(int capacity)
    {
        int size = HashHelpers.GetPrime(capacity);
        ...
        entries = new Entry[size];
        ...
    }

当我重现这个时,错误发生在数组创建上。在这种情况下,Entry 是一个大小为 24 的结构。当我们得到 max int32 (0x80000000-1) 并除以 24 = 89478485 并且这个数字介于素数 89478457 和 89478503 之间时。

这是否意味着结构数组不能像 maxInt32/sizeOfThisStruct 一样大?

编辑:

是的。我实际上超过 2 GB。当字典创建 struct Entry 的内部数组时,就会发生这种情况,(key,value) 对存储在哪里。在我的例子中,sizeof(Entry) 是 24 字节,并且作为值类型是内联分配的。

解决方案是使用gcAllowVeryLargeObjects 标志(谢谢Evk)。实际上在 .net 核心中,标志是the environment variable COMPlus_gcAllowVeryLargeObjects(谢谢svick)。

是的,Paparazzi 是对的。我得想一想,如何不浪费内存。 谢谢你们。

【问题讨论】:

  • 我想知道你为什么需要这么大的字典?这种考验的真正实用性是我所质疑的
  • @BenPhilipp Int 仅用于测试。实际上是一个结构体。
  • @MukeshAdhvaryu 你将使用什么来创建稀疏 3d 数组。

标签: c# .net-core .net-core-rc2


【解决方案1】:

.NET 运行时存在已知限制 - 堆上允许的最大对象大小为 2 GB,即使在 64 位版本的运行时也是如此。但是,从 .NET 4.5 开始,configuration option 允许您放宽此限制(仅在 64 位版本的运行时)并创建更大的数组。要启用的配置示例是:

<configuration>
  <runtime>
    <gcAllowVeryLargeObjects enabled="true" />
  </runtime>
</configuration>

【讨论】:

  • 这对 .Net Core 是否同样有效?我认为 .Net Core 不使用 app.config。
  • 感谢您的信息。似乎您的链接回答了您的问题。我已经测试过,没有该选项的行为似乎相同(因此在分配太大的数组时它也会抛出 OutOfMemoryException)。
  • @Evk 这与 2GB 限制无关。我离2GB还很远。
  • @Motor 不,你离 2GB 不远了。它需要连续的内存。
  • @Motor 只需应用提到的配置更改,看看异常如何消失。此限制与您拥有的内存量无关 - 即使您有 TB 也适用。
【解决方案2】:

表面上字典没有意义
您只能拥有 int 唯一值
你真的有我的副本吗

UnInt32 转到 4,294,967,295
为什么要浪费 4 个字节?

89,478,458 行 当前一行是 12 个字节
您在大约 83,333,333 行中有 1 GB
由于一个对象需要连续的内存 1 GB 是一个实际的限制

如果 values 真的是一个支柱 24
然后 1 GB 在 31,250,000

这只是一个非常大的集合

您可以拆分为多个集合

或者使用一个类,因为它只是一个引用,我认为是 4 个字节

【讨论】:

  • 在 UInt64 中是 3D Array (X,Y,Z) 编码的位置,值是数组中的值。它们由用户 (SQL) 动态填充,并且数组是稀疏的。然后还有很多计算。
  • 那么我建议更有效的编码,因为你会浪费很多空间。
  • 它是用位掩码编码的。在现实中,正常大小在 100000 到 500000 之间,但我应该知道限制在哪里,因为我对编译时的数据一无所知。
  • 所以你不知道大小。这不是一个确切的数字,因为连续内存受其他因素的影响。您正在浪费大量空间,而您似乎只关心向它投入更多内存。
  • 你能告诉我你的建议吗?如何在一个低于 int64 大小的键中编码 3 个 int 并且它们编码速度很快?如果您看到该值,它是 int 而不是 struct 24 字节。什么24字节的struct是C#字典的内部实现(点击链接)Elem struct。
猜你喜欢
  • 1970-01-01
  • 2016-08-20
  • 1970-01-01
  • 2015-04-29
  • 1970-01-01
  • 2016-06-12
  • 2016-08-17
  • 2023-03-20
  • 2014-10-26
相关资源
最近更新 更多