2009-06-12 4 views
3

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

SetLength(dynArray, High(Int64)); 

Это имеет значение 9,223,372,036,854,775,807, и я полагаю, что было бы наибольшее количество индексов, я мог бы ссылаться в любом случае. Это дало мне a:

ERangeError с сообщением «Ошибка проверки диапазона».

Так что я пробовал:

SetLength(dynArray, MaxInt); 

и получил ту же ошибку!

Интересно я мог бы назвать его

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

Что на самом деле в два раза больше MaxInt!

Я попытался

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

Что такое же, как High (Int64), и это тоже не получилось.

Короткие продолженные испытания и ошибки, кто-то знает максимальный размер? Это зависит от размера элементов в массиве?

Я использую Delphi 2009. Это будет отличаться для разных версий (очевидно, когда Commadore выходит оно должно быть больше!)

+3

Вы действительно ожидали, что распределение 9 экзабайт (или более) памяти будет работать? :) – Thorarin

+0

Нет, мне это не понравилось, но мне было любопытно, если я получу память или ошибку диапазона. –

+0

Typo в названии, Jim ;-) –

ответ

17

Ответ ясен из системы.Процедура DynArraySetLength, от линии 20628:

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

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

+0

Ах, хорошая находка. Интересно, что я не получил проверку диапазона (или из Mem) с вызовом SetLength (dynArray, Trunc (Power (2, 32)), возможно, он обернут всю дорогу! –

+2

RTL резервирует пространство для двух LongInts чтобы сохранить длину и количество ссылок. –

+0

С новыми версиями Delphi с 64-битной целью у вас могут быть даже более длинные массивы. – Kromster

4

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

Размер структуры данных и содержащихся в ней данных должен быть меньше максимальной памяти, которую может распределить приложение, за вычетом памяти сам код приложения, стек и другие данные. В 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(), это единственный способ убедиться, что компилятор и среда выполнения сделали то, что вы намеревались.

+0

Итак, вы говорите, что мы не можем полагаться на SetLength, чтобы на самом деле работать, даже если он не вызывает исключение, но должен проверить фактическую длину массива впоследствии? Это волнует. – dummzeuch

+0

Нет, извините. Я отредактирую свой ответ, при повторном чтении это неясно. То, что я пытался сказать, заключается в том, что предоставление длины int64 и отсутствие исключения не означает, что операция преуспела, наивысшие 32 бита можно было бы отменить, если проверка диапазона была отключена. – mghie

1

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

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; 
Смежные вопросы