Max length for a dynamic array in Delphi?

16,260

Solution 1

The answer is clear from System.DynArraySetLength procedure, from line 20628:

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

The maximum value you can allocate without raising a range check error is therefore theoretically Maxint - SizeOf(Longint) * 2. Practically, you will get an out-of-memory error depending on how much memory is available.

Solution 2

There's no point in speculating about the maximum theoretical length of a dynamic array, as the maximum practical length is much smaller.

The size of the data structure and the data contained in it has to be smaller than the maximum memory an application can allocate, minus the memory the application code itself, the stack and the other data will need. On Windows (32 bit, the only version we mere mortals can target with Delphi right now) this is a virtual address range of 2 GByte, or 3 GByte with a special switch for the OS loader, for each application. I'm not sure though that a Delphi application can even handle the 3 GByte memory space, as the last third would have negative values for offsets in all places where integers are used instead of LongWords.

So you could try to allocate a dynamic array of say 80% or 90% of MaxInt div SizeOf(array element) - with the most probable result that the allocation of that memory block fails at runtime.

Also: giving an int64 length and getting no exception would not mean that the array has the intended length. Consider this code:

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

If range checking is off this will compile without hints and warnings, and run without exceptions. It has only the slight problem that the array has length 0 after the call to SetLength(). So for the checks in your question you should definitely read back the length of the dynamic array after a successful SetLength(), it is the only way to be sure that the compiler and runtime did what you intended.

Solution 3

Note that afaik elementcount is also limited, more than 2^31-1 is unlikely. It could be that size has the same limit (to avoid signed<>unsigned issues in the RTL) I doubt that more of than 2GB is possible even in /3GB mode.

Solution 4

MMaths:

max_array_bytesize = 2^31 - 9

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

Code:

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

Example:

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;
Share:
16,260
Joel
Author by

Joel

Developer Advocate for Embarcadero Technologies Invented and patented swipe to unlock in 2000. See US Patent # 8352745 &amp; 6766456, and others. Host of the Podcast at Delphi.org. (mostly a blog with occasional episodes). Preferred Languages: Delphi / Object Pascal C++ JavaScript C# / .NET Java

Updated on July 04, 2022

Comments

  • Joel
    Joel almost 2 years

    I was curious how long a dynamic array could be so I tried

    SetLength(dynArray, High(Int64));
    

    That has a value of 9,223,372,036,854,775,807 and I figure that would be the largest number of indexes I could reference anyway. It gave me a:

    ERangeError with message 'Range check error'.

    So I tried:

    SetLength(dynArray, MaxInt); 
    

    and got the same error!

    Interestingly I could call it with

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

    Which is actually twice the size of MaxInt!

    I tried

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

    Which is the same as High(Int64), and that failed too.

    Short of continued trial and error, does someone know the maximum size? Does it depend on the size of the elements in the array?

    I am using Delphi 2009. Will it be different for different versions (obviously when Commadore comes out it should be greater!)

  • Joel
    Joel almost 15 years
    Ah, good find. Interesting that I didn't get a Range Check (or out of Mem) with the call SetLength(dynArray, Trunc(Power(2, 32)); Maybe it wrapped all the way around!
  • dummzeuch
    dummzeuch almost 15 years
    So you are saying that we cannot rely on SetLength to actually work even if it does not raise an exception but have to check the actual length of the array afterwards? That's worrying.
  • mghie
    mghie almost 15 years
    No, sorry. I'll edit my answer, on re-reading it is quite unclear. What I was trying to say is that giving an int64 length and getting no exception doesn't mean the operation succeeded, the highest 32 bits could have been silently discarded if range check was off.
  • Rob Kennedy
    Rob Kennedy almost 15 years
    The RTL is reserving space for two LongInts in order to hold the length and reference count.
  • Kromster
    Kromster about 10 years
    Since new Delphi versions with 64bit target you can have even longer arrays.