Форум: "Основная";
Поиск по всему сайту: delphimaster.net;
Текущий архив: 2002.03.28;
Скачать: [xml.tar.bz2];




Вниз

Динамические массивы в Дельфи 


Vladimir1   (2002-03-09 20:27) [0]

Необходимо зачитать текстовый файл большого объема (до 6 Мб.) в массив (для сортировки строк), но Дельфи не дает создать массив соответствующего размера, даже динамический. Может кто знает, как лучше создавать динамические массивы в этом случае?



Anatoly Podgoretsky   (2002-03-09 20:37) [1]

Дельфи позволяет создавать стуктруры данных до 2 гб, все динамические массивы создаются с помощью прцедуры SetLength



Vladimir1   (2002-03-09 20:58) [2]

Ругается Дельфи, но если в Setlength установить несколько десятков тысяч, то все нормально работает. Мне хотя бы пример реально работающей конструкции на большое количество элементов массива.



Anatoly Podgoretsky   (2002-03-09 21:12) [3]

Как ругаетс, видимо секрет.



drpass   (2002-03-09 23:17) [4]

Наверное, он пишет array of string размером несколько сотен тысяч строк. Я, конечно, так не извращался, но сомневаюсь в возможностях менеджера памяти Delphi, да и любого другого компилятора.
Может, попробовать TStringList?



Anatoly Podgoretsky   (2002-03-09 23:21) [5]

Это потребует еще больше памяти, а сто тысяц строк скажкм при длине 80 байт ничтожно малая величина, я спокойно обрабатывал свыше миллиона и не по 80 символов. У нег явно что то другое, вот только говорить не хочет, ну это его дело, видимо сам решит.



lipskiy   (2002-03-10 00:07) [6]

Я немного не в тему, хотя кто его знает...
Был у меня случай, когда я текстовый файл читал в динамический массив. Строк около 100 тыс, длиной разной, в среднем символов 200. Так вот, поскольку числа строк заранее не известно (а посчитать их перед заполением массива сразу в голову не пришло), то я при прочтении новой строки делал в цикле SetLength(ar,Length(ar)+1) и вносил новую строчку. При такой операции где-то на 60-ти тысячах строк выдавалась не помню какая ошибка (давно было), но что-то про недостаток ресурсов. Долго репу чесал, так как памяти физической полно было, ну и для проверки решил сразу оттяпать кусок на 200 тыс. строк, заполнить его а лишнее потом отрубить. И прошло, как ни странно! Я и больше оттяпывал - проходило! А вот построчно наращивать, то есть поэлементно (для массива) - затыкается... Природа этого явления мне самому не очень ясна. Если кто знает - почему так, мне было бы интересно послушать. М.б. и у Vladimir1 проблема в этом.



drpass   (2002-03-10 00:47) [7]

Вероятно, дело в фрагментации памяти - при большом количестве выделений постепенно карта распределения памяти превращается в "зебру", и менеджер рано или поздно просто не находит непрерывного фрагмента требуемой длины (можно посмотреть на это функцией GetHeapStatus). А сразу выхватить большой кусок из памяти, пока она еще не фрагментирована, удается без проблем.



lipskiy   (2002-03-10 01:04) [8]

Я, может, плохо понимаю структуру распределения памяти, но думаю так (может, и не верно).
Изначально для программы выделяется область, затем, по мере ее прожорливости, система отводит все новые и новые участки, какие-то освобождаются, какие-то занимаются вновь. Да, получается "зебра". Но ведь в памяти сидит много программ одновременно, и все они (ну не все, но некоторые) тоже пользуются ресурсами неровно и создают ту самую зебру еще до запуска моей программы. То есть, к моменту запуска память (если ОС давно не перегружалась) уже сильно фрагментирована и вроде бы не всегда должно однозначно можно мне выделить большой непрерывный участок. Или все это совсем не так?



Anatoly Podgoretsky   (2002-03-10 10:04) [9]

Думаю не так, каждый процесс излдирован от другого, а память виртуальная.



drpass   (2002-03-10 12:14) [10]

Память-то виртуальная, но Windows выделяет ее из физической. Менеджер памяти Delphi, по сути, единственное, что делает - вызывает стандартные функции винды malloc и realloc. Насколько я понял из документации и исходников, выторговав единый кусок памяти у винды, менеджер затем распределяет его по запросам объектов, при необходимости расширяя страницами по 16К. Вот в нем-то и может возникнуть фрагментация



Anatoly Podgoretsky   (2002-03-10 12:17) [11]

Бе з разницы, физическая память это промежуточное место для работы процессора



drpass   (2002-03-10 12:35) [12]

А как тогда это объяснить?



Anatoly Podgoretsky   (2002-03-10 12:41) [13]

Дефрагментация в рамках процесса



Yuri-7   (2002-03-10 14:11) [14]

Все-таки согласен с drpass - во всех отношениях лучше использовать TStringList. И загружать из файла удобно, и сортировать можно, как пожелаешь.



Vladimir1   (2002-03-10 20:12) [15]

Использовал String, а как ругается Дельфи, не помню, могу позже уточнить. Setlength использовал 1 раз и выделял даже больше, чем нужно (немного), так как в тестовом файле я знал, сколько там строк.
Длина каждой строки не более, чем на этой странице.
Попробую Tstringlist.



Набережных С.   (2002-03-10 21:33) [16]


> Vladimir1 (10.03.02 20:12)

Лучше бы показал код. 6 мегабайт немного, совсем не много.
Вот этот код нормально работает, а выделяется почти 100 мегабайт. А файл больше 7 мег.

Fs:TFileStream;
Arr:array of byte;
begin
Fs:=TFileStream.Create("C:\Program Files\Borland\CBuilder5\Lib\vcl50.csm",fmOpenRead);
try
SetLength(arr,100000000{Fs.Size+1});
try
Fs.Read(Arr[0],Fs.Size);
Memo1.Lines.Text:=PChar(Copy(Arr,$2000,300));
finally
SetLength(Arr,0);
end;
finally
Fs.Free;
end;
end;



Vladimir1   (2002-03-14 15:07) [17]

Вот текст:

procedure TForm1.Button1Click(Sender: TObject);
var f1,f2:textfile;
s1:array [1..500000] of string;
s:array [1..500000,1..4] of string;
{tim:array [1..1000,1..10] of tdatetime;}
i,j,k,finds,c,dur1,dur2:integer;
m:string;
timea1,timeb1,timea2,timeb2:tdatetime;
begin
assignfile(f1,"out.txt");
reset(f1);
assignfile(f2,"bbb.txt");
rewrite(f2);
i:=0;
while not eof(f1) do begin
inc(i);
readln(f1,s1[i]);
end;
for j:=1 to i do begin
finds:=pos(" 2503947",s1[j]);
if finds>0 then begin
s[j,1]:=copy(s1[j],15,8);
s[j,2]:=copy(s1[j],37,8);
s[j,3]:=copy(s1[j],50,8);
m:=s1[j];
c:=6;
if (m[63]=" ") and (m[64]<>" ") and (m[65]<>" ")
and (m[66]<>" ") and (m[67]<>" ") then c:=0;
if (m[63]=" ") and (m[64]=" ") and (m[65]<>" ")
and (m[66]<>" ") and (m[67]<>" ") then c:=1;
if (m[63]=" ") and (m[64]=" ") and (m[65]=" ")
and (m[66]<>" ") and (m[67]<>" ") then c:=2;
if (m[63]=" ") and (m[64]=" ") and (m[65]=" ")
and (m[66]=" ") and (m[67]<>" ") then c:=3;
if (m[63]=" ") and (m[64]=" ") and (m[65]=" ")
and (m[66]=" ") and (m[67]=" ") then c:=4;
if c=4 then s[j,4]:=copy(s[j],68,1);
if c=3 then s[j,4]:=copy(s1[j],67,2);
if c=2 then s[j,4]:=copy(s1[j],66,3);
if c=1 then s[j,4]:=copy(s1[j],65,4);
if c=0 then s[j,4]:=copy(s1[j],64,5);
end;
end;
for j:=1 to i do begin
timea1:=strtodatetime(s[j,2]+" "+s[j,3]);
dur1:=strtoint(s[j,4]);
timeb1:=timea1+dur1/86400;
if j+1<=i then begin
timea2:=strtodatetime(s[j+1,2]+" "+s[j+1,3]);
dur2:=strtoint(s[j+1,4]);
timeb2:=timea2+dur2/86400;
if timeb1>timea2 then begin
write(f2,s[j,1]);
write(f2," ");
write(f2,s[j,2]);
write(f2," ");
write(f2,s[j,3]);
write(f2," ");
write(f2,s[j,4]);
write(f2," ");
write(f2,datetimetostr(timea1));
write(f2," ");
write(f2,datetimetostr(timeb1));
write(f2," ");
write(f2,datetimetostr(timea2));
write(f2," ");
writeln(f2,datetimetostr(timeb2));
end;
end;
end;
closefile(f1);
closefile(f2);
end;

Это с обычными массивами, с динамическими - аналогично ругается.



Набережных С.   (2002-03-14 17:54) [18]

М-да...
Вариантов несколько:
1. Увеличить стек мег до десяти.
2. Объявить массивы глобально :(
3. Выделять динамически. Например, так:

var
s1:array of string;
s:array of array of string;
....
SetLength(S1,500000);
SetLength(s,4);
SetLength(s[0],500000);
SetLength(s[1],500000);
SetLength(s[2],500000);
SetLength(s[3],500000);

и не забыть освободить:

s1:=Copy(s1,0,0);
S[0]:=Copy(s[0],0,0);
S[1]:=Copy(s[1],0,0);
S[2]:=Copy(s[2],0,0);
S[3]:=Copy(s[3],0,0);
S:=Copy(s,0,0);



Anatoly Podgoretsky   (2002-03-14 21:59) [19]

Набережных С. (14.03.02 17:54)
1. Увеличить стек мег до десяти.

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



Набережных С.   (2002-03-15 16:56) [20]


> Anatoly Podgoretsky © (14.03.02 21:59)

Да, думаю, на нехватку стека и ругается. А размер я на глазок прикинул: 10 млн. на массивы, остается еще 480 тысяч с мелочью - вроде должно на остальное хватить. Или я что-то упускаю?
А вообще непонятно, на кой ляд сразу весь файл в память тащить?



Donal_Graeme   (2002-03-15 17:14) [21]

попробовал я компильнуть тот кусок кода и вот что получил :

Incompatible types в стороке

if c=4 then s[j,4]:=copy(s[j],68,1);

что, конечно же, логично :-)))

ведь ошибка и правда не была озвучена



Anatoly Podgoretsky   (2002-03-15 21:05) [22]

SetLength(S1,500000); 2иб
SetLength(s,4);
SetLength(s[0],500000); 2иб
SetLength(s[1],500000); 2иб
SetLength(s[2],500000); 2иб
SetLength(s[3],500000); 2иб

4*500000=2000000*4 = 8 мб только на указатели для s + еще для S1 500000*4?, всего 10 иб только на указатели массива, сами строки не рассматриваю, они как бы не на стеке. Ну может остатка и хватит на все осталное, но я бы не стал так рисковать.

Donal_Graeme (15.03.02 17:14)
а чего другого ожидать, массмв то двухмерный, потому и говорю Anatoly Podgoretsky © (09.03.02 21:12).




Форум: "Основная";
Поиск по всему сайту: delphimaster.net;
Текущий архив: 2002.03.28;
Скачать: [xml.tar.bz2];




Наверх





Память: 0.77 MB
Время: 0.044 c
4-91122           Sashak                2002-01-28 21:49  2002.03.28  
Как добраться к свойствам системной кнопки


1-90866           baston                2002-03-16 19:15  2002.03.28  
Что представляет из себя компонент ValueListEditor и как с ним работать


1-90972           ivit61                2002-03-13 10:52  2002.03.28  
Поиск метода по адресу


7-91090           Pat                   2001-12-26 12:56  2002.03.28  
WinExec( C: con con ,sw_restore)


3-90803           arnold lane           2002-03-04 20:59  2002.03.28  
вопрос