Delphi中动态数组的最大长度是多少?

7

我很好奇动态数组的最大长度是多少,所以我试了一下。

SetLength(dynArray, High(Int64));

这个值是9223372036854775807,我认为这应该是我可以引用的最大索引数。但是程序报错:

ERangeError with message 'Range check error'.

于是我尝试了:

SetLength(dynArray, MaxInt); 

我尝试了相同的操作,但是出现了错误!

有趣的是,我可以使用以下方式进行调用:

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

这实际上是MaxInt大小的两倍!

我尝试过

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

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

除了不断尝试外,有人知道最大大小吗?它是否取决于数组中元素的大小?

我正在使用Delphi 2009。对于不同版本会有所不同吗(显然,当Commadore出现时,应该会更大!)


5
你真的期望分配9艾字节(或更多)的内存会奏效吗? :) - Thorarin
不,我没有,但我很好奇会得到一个内存错误还是范围错误。 - Jim McKeeth
1
在32位Delphi中,动态数组的SetLength函数接受一个类型为Integer的长度参数。因此,尝试传递Int64有点无意义。我本来希望编译器会对此发出警告。实际上会发生的是,64位整数的最高32位将被截断。 - David Heffernan
4个回答

20

答案可以从 System.DynArraySetLength 这个过程中得出,该过程在第20628行。

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

理论上,您可以分配的最大值而不引发范围检查错误是Maxint-SizeOf(Longint)* 2。实际上,根据可用多少内存,您将获得 out-of-memory 错误。


啊,好发现。有趣的是,我没有在调用SetLength(dynArray, Trunc(Power(2, 32))时得到范围检查(或内存不足)错误。也许它完全绕了一圈! - Jim McKeeth
3
RTL 预留了空间以容纳两个 LongInt 变量,用于存储长度和引用计数。 - Rob Kennedy
自从新版本的Delphi支持64位目标后,您可以拥有更长的数组。 - Kromster

5

关于动态数组的最大理论长度,纯属猜测没有意义,因为实际可用的最大长度要小得多。

数据结构的大小和其中包含的数据必须小于应用程序可以分配的最大内存减去应用程序代码本身、堆栈和其他数据所需的内存。在Windows上(32位,目前Delphi只能针对这个版本进行开发),每个应用程序的虚拟地址范围为2GB,或者使用OS加载器的特殊开关后为3GB。但我不确定Delphi应用程序是否能处理3GB的内存空间,因为最后1/3的整数偏移值将变成负数,而不是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没有引发异常,我们也不能依赖它实际起作用,而必须在之后检查数组的实际长度?这令人担忧。 - dummzeuch
不好意思,我会编辑我的回答,因为重新阅读后它非常不清楚。我的意思是,给定一个int64长度并且没有抛出异常并不意味着操作成功,如果范围检查关闭,则最高的32位可能已被静默丢弃。 - mghie

1

MMaths:

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;

1
请注意,afaik元素计数也是有限制的,超过2 ^ 31-1是不太可能的。可能大小也有相同的限制(为了避免RTL中的signed <> unsigned问题),即使在/ 3GB模式下,我也怀疑超过2GB是不可能的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接