【问题标题】:Why is "long" being allowed as array length in C#?为什么在 C# 中允许“long”作为数组长度?
【发布时间】:2012-06-12 07:26:08
【问题描述】:

我想尝试分配一个 40 亿字节的数组,这是我的 C# 代码:

long size = 4 * 1000;
size *= 1000;
size *= 1000;
byte[] array = new byte[size];

此代码在包含new 的行上出现System.OverflowException 失败。好的,原来Length 返回int,所以数组长度也限制在int 可以存储的范围内。

那为什么没有编译时错误,并且允许long作为分配时的数组元素个数?

【问题讨论】:

  • Array.CreateInstance() 给出更有意义的错误消息,“不支持大于 2GB 的阵列。”
  • 所以您分配了 3.7 GB 的内存。您的机器上安装了多少 RAM? :D
  • @Joso:这是一个 64 位进程,所以由于分页,它可以分配 3.7,因为有足够的磁盘空间。
  • 即使分页也有其局限性。假设 1024 MB 物理 RAM,Windows 通常会将页面文件限制为 1536 MB。结合起来,您将能够分配 2560 MB 的内存。由于 Windows 将上页文件大小设置为物理内存的 1.5 倍,我会说物理 RAM 可能不是限制因素,但它是一个因素。
  • JoSo,(a) 没有一个头脑正常的人会在 1 GiB 内存上使用 64 位 Windows; (b) 现在内存非常便宜,所以任何小于 8 GiB 的内存都毫无意义; (c) 你读过答案吗?问题完全是另外一回事。

标签: c# .net memory-management buffer-overflow


【解决方案1】:

因为规范在第 7.6.10.4 节中是这样说的:

表达式列表中的每个表达式都必须是 intuintlongulong 类型,或者可以隐式转换为其中一种或多种类型。

这很可能很容易允许创建大于 2 GiB 的数组,即使它们不受支持(但将没有 语言 一旦 CLR 做出这样的改变就改变)。 Mono does support this, however.NET 4.5 apparently will allow larger arrays too

顺便说一下关于数组长度是int:还有LongLength,返回一个long。这是 .NET 1.1 中的内容,可能是面向未来的更改。

【讨论】:

  • +1 4.5 的好地方,希望上帝我从来没有在我们的应用程序中看到过这种情况...
  • 看起来即使更改了 4.5,相关代码仍然会失败,因为它说“对于字节数组和单字节结构的数组,任何单个维度的最大索引是 2,147,483,591 (0x7FFFFFC7),其他类型为 2,146,435,071 (0X7FEFFFFF)。”
  • 确实如此。然后,您可以将其设为多维数组来解决此问题。但这也很糟糕。
  • @ErenErsönmez 你写了“它说...”它在哪里说的?
  • @Mishax:在我的答案中包含的第二个链接中。
【解决方案2】:

为什么允许长作为数组长度?

答案是:.net 中的 long 表示 Int64

根据规范,数组索引可以是Int64。

第二个问题:为什么会显示溢出异常?

因为任何单个对象不能分配超过 2GB 的内存。

【讨论】:

  • 有了这样的声明(除非它们很明显,例如 longSystem.Int64 的别名),用引用来支持它们总是很好的。
  • 我不同意你的第二点。如果内存不足,您应该期待 OutOfMemoryException,而不是 OverflowException。根据规范,仅当长度小于零时才应引发 OverflowException。
  • @Mishax:不是内存不足,只是单个对象不能大于那个。
  • @Joey 你可能是对的,但我指的是 mdkamruzzaman 对 OverflowException 的解释。在 C# 语言规范中,它指出如果任何维度长度说明符小于零,则可以引发 OverflowException。就是这样,这是唯一的原因。我在语言规范中找不到任何关于 2GB 限制的内容。这里有一些讨论:stackoverflow.com/questions/14889333/…
【解决方案3】:

这是CLR的限制,单个对象不能超过2GB,包括数组:

Large array C# OutOfMemoryException

这与 32 位或 64 位操作系统无关。也就是说,它不会阻止您使用超过该数量的总量,只是不会在一个对象上使用。

这是一个运行时错误,因为如果您将long(或其他初始化值)保持在范围内,它将起作用。

您可以使用所有整数类型初始化数组:sbytecharshortintlong - 全部编译;未签名的变体也可以。

【讨论】:

    【解决方案4】:

    .Net 4.5-4.6 中有一个解决方案允许数组使用大尺寸。

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

    See documentation.

    【讨论】:

      【解决方案5】:

      long是整数类型,所以可以用来定义数组;例外是构建过大的数组,而不是使用long

      例如,这很好用:

      long size = 20;
      byte[] array = new byte[size];
      

      【讨论】:

        猜你喜欢
        • 2011-02-06
        • 2011-10-15
        • 2013-08-02
        • 1970-01-01
        • 2012-02-14
        • 2019-06-08
        • 1970-01-01
        • 2014-05-05
        • 1970-01-01
        相关资源
        最近更新 更多