views:

1637

answers:

3

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!)

+3  A: 

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.

mghie
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.
dummzeuch
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.
mghie
+12  A: 

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.

TOndrej
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!
Jim McKeeth
The RTL is reserving space for two LongInts in order to hold the length and reference count.
Rob Kennedy
+1  A: 

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.

Marco van de Voort