Максимальная длина динамического массива в Delphi? - PullRequest
5 голосов
/ 12 июня 2009

Мне было любопытно, как долго может быть динамический массив, поэтому я попытался

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, он должен быть больше!)

Ответы [ 4 ]

18 голосов
/ 12 июня 2009

Ответ ясен из процедуры System.DynArraySetLength, из строки 20628:

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

Следовательно, максимальное значение, которое вы можете выделить без увеличения ошибки проверки диапазона, теоретически Maxint - SizeOf (Longint) * 2. Практически вы получите ошибку нехватки памяти в зависимости от того, сколько памяти доступно.

5 голосов
/ 12 июня 2009

Нет смысла рассуждать о максимальной теоретической длине динамического массива, так как максимальная практическая длина намного меньше.

Размер структуры данных и содержащихся в ней данных должен быть меньше, чем максимальный объем памяти, который может выделить приложение, минус память, необходимая самому коду приложения, стеку и другим данным. В Windows (32-битная, единственная версия, которую мы, простые смертные, можем нацелить прямо сейчас с Delphi), это виртуальный диапазон адресов 2 ГБ или 3 ГБ со специальным переключателем для загрузчика ОС для каждого приложения. Однако я не уверен, что приложение Delphi может даже обрабатывать 3 ГБ памяти, поскольку последняя треть будет иметь отрицательные значения для смещений во всех местах, где используются целые числа вместо LongWords.

Таким образом, вы можете попытаться выделить динамический массив, скажем, 80% или 90% от MaxInt div SizeOf(array element) - с наиболее вероятным результатом того, что выделение этого блока памяти завершится неудачно во время выполнения.

Также: указание длины int64 и отсутствие исключений не означает, что массив имеет предполагаемую длину. Рассмотрим этот код:

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

Если проверка диапазона выключена, она будет компилироваться без подсказок и предупреждений и работать без исключений. Есть только небольшая проблема, что массив имеет длину 0 после вызова SetLength () . Так что для проверок в вашем вопросе вы должны обязательно прочитать длину динамического массива после успешного SetLength () , это единственный способ убедиться, что компилятор и среда выполнения сделали то, что вы хотели.

1 голос
/ 14 октября 2013

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 голос
/ 13 июня 2009

Обратите внимание, что afaik elementcount также ограничен, более 2 ^ 31-1 маловероятно. Возможно, размер имеет одинаковое ограничение (во избежание проблем со знаком <> без знака в RTL), я сомневаюсь, что в режиме / 3GB возможно более 2 ГБ.

...