【问题标题】:Max length for a dynamic array in Delphi?Delphi中动态数组的最大长度?
【发布时间】:2009-06-12 04:34:46
【问题描述】:

我很好奇动态数组可以有多长,所以我尝试了

SetLength(dynArray, High(Int64));

它的值为 9,223,372,036,854,775,807,我认为这将是我可以参考的最大索引数。它给了我一个:

带有“范围检查错误”消息的 ERangeError。

所以我尝试了:

SetLength(dynArray, MaxInt); 

得到了同样的错误!

有趣的是,我可以用它来称呼它

SetLength(dynArray, Trunc(Power(2, 32));

实际上是 MaxInt 大小的两倍!

我试过了

SetLength(dynArray, Trunc(Power(2, 63) - 1));

这与 High(Int64) 相同,但也失败了。

没有持续的反复试验,有人知道最大尺寸吗?是否取决于数组中元素的大小?

我用的是Delphi 2009,不同版本会不会不一样(很明显Commadore出来的时候应该会更好!)

【问题讨论】:

  • 您真的期望分配 9 艾字节(或更多)的内存会起作用吗? :)
  • 不,我没有,但我很好奇是否会出现内存或范围错误。
  • 在 32 位 Delphi 中,SetLength 用于动态数组,采用 Integer 类型的长度参数。所以试图通过Int64 有点毫无意义。我希望编译器会对此发出警告。发生的情况是 64 位整数的最高有效 32 位被截断。

标签: delphi delphi-2009


【解决方案1】:

从第 20628 行的 System.DynArraySetLength 过程中可以清楚地看到答案:

Inc(neededSize, Sizeof(Longint)*2);
if neededSize < 0 then
  Error(reRangeError);

因此,理论上,您可以在不引发范围检查错误的情况下分配的最大值为 Maxint - SizeOf(Longint) * 2。实际上,根据可用内存量,您会收到内存不足错误。

【讨论】:

  • 啊,很好的发现。有趣的是,我没有通过调用 SetLength(dynArray, Trunc(Power(2, 32)); 得到范围检查(或超出 Mem);也许它一直环绕!
  • RTL 为两个 LongInt 保留空间,以保存长度和引用计数。
  • 自从有了 64 位目标的新 Delphi 版本,您可以拥有更长的数组。
【解决方案2】:

推测动态数组的最大理论长度没有意义,因为最大实际长度要小得多。

数据结构和其中包含的数据的大小必须小于应用程序可以分配的最大内存,减去应用程序代码本身、堆栈和其他数据所需的内存。在 Windows 上(32 位,我们普通人现在可以使用 Delphi 的唯一版本)这是每个应用程序的 2 GByte 或 3 GByte 的虚拟地址范围,带有用于 OS 加载程序的特殊开关。我不确定 Delphi 应用程序是否可以处理 3 GB 内存空间,因为在所有使用整数而不是 LongWords 的地方,最后三分之一的偏移量都是负值。

因此,您可以尝试分配一个动态数组,例如分配 MaxInt div SizeOf(array element) 的 80% 或 90% - 最可能的结果是该内存块的分配在运行时失败。

另外:给出一个 int64 长度并且没有异常并不意味着数组具有预期的长度。考虑这段代码:

procedure TForm1.Button1Click(Sender: TObject);
var
  a: array of byte;
  l: int64;
begin
  l := $4000000000;
  SetLength(a, l);
  Caption := IntToStr(Length(a));
end;

如果关闭范围检查,这将在没有提示和警告的情况下编译,并且无异常运行。在调用 SetLength() 之后,数组的长度为 0 只是一个小问题。因此,对于您问题中的检查,您绝对应该在成功 SetLength() 后读回动态数组的长度,这是确保编译器和运行时执行您的预期的唯一方法。

【讨论】:

  • 所以你是说我们不能依赖 SetLength 来实际工作,即使它没有引发异常但必须在之后检查数组的实际长度?这令人担忧。
  • 不,抱歉。我将编辑我的答案,重新阅读时还不清楚。我想说的是,给出一个 int64 长度并且没有异常并不意味着操作成功,如果关闭范围检查,最高 32 位可能会被静默丢弃。
【解决方案3】:

请注意,afaik elementcount 也是有限的,不可能超过 2^31-1。可能是大小具有相同的限制(以避免 RTL 中的有符号无符号问题)我怀疑即使在 /3GB 模式下也可能超过 2GB。

【讨论】:

    【解决方案4】:

    数学:

    max_array_bytesize = 2^31 - 9

    max_array_elements_number = [(2^31 - 9) / array_element_bytesize]

    代码:

    max_array_elements_number := (MaxInt-Sizeof(Longint)*2) div SizeOf(array_element);
    

    例子:

    type
      TFoo = <type_description>;
      TFooDynArray = array of TFoo
    const
      cMaxMemBuffSize = MaxInt-Sizeof(Longint)*2;
    var
      A : TFooDynArray;
      B : array of int64;
      MaxElems_A : integer;
      MaxElems_B : integer;
    begin
      MaxElems_A := cMaxMemBuffSize div SizeOf(TFoo);
      MaxElems_B := cMaxMemBuffSize div SizeOf(int64);
    
      ShowMessage('Max elements number for array:'#13#10+
                  '1) A is '+IntToStr(MaxElems_A)+#13#10+
                  '2) B is '+IntToStr(MaxElems_B)
                  );
    end;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-16
      • 2020-11-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多