Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Не хватает памяти. [D5, D6, Win95/98, Win2k]


Страницы:   1 2 3

opoloXAI ©   (2004-07-12 12:02:00) 

Добрый день.
На Celeron400 с 65МГбт свободной памяти я динамически увеличиваю размер массива следующего типа:
type
TMyMassiv = record
 v1: String;
 v2: String;
 v3: Integer;
end;{record}
var
mas: array of TMyMassiv;
Увеличиваю количество элементов массива на один и добавляю новый элемент. При достижении числа элементов массива около 4000..5000 сбодной памяти остается 0 Кбт. Дальше работа программы превращается в полные "тормоза".
Вероятнее всего я нерационально отнесся к памяти, наверное стоило воспользоваться TStream. Но я не знаю как пользоваться структурой TStream of TMyMassiv. Подскажите примерчиком кода.
Заранее спасибо.


Тимохов   (2004-07-13 12:45:00) [41]


> han_malign ©   (13.07.04 11:27) [9]
> при SetLength(...,Length()+1), занимается память на 2*Length()+1(по
> грубым прикидкам)

да...
прикидки и правда грубые.
Вы это сами придумали?


> Что такое фрагментация памяти знаешь?

А вы знаете? Вы знаете как работает с фрагментами манагер памяти дельфи?


Ega23   (2004-07-13 11:33:00) [42]

Я бы воспользовался TList.

public
List:TList; // объявил список, создать его в OnFormCreate,
           

procedure TSameForm.AddFile(SchRec: TSearchRec; Dir: String);
var
p:PmySearchRec
begin
  New(P);
  P^.Size:=SchRec.Size;
  P^.Name:=AnsiUpperCase(SchRec.Name);
  P^.Path:=Dir;
  List.Add(P);    GetPamat:=GetPamat+SizeOf(SchRec.Size)+SizeOf(SchRec.Name)+SizeOf(Dir);
end;

Только не забудь на FormDestroy сделать Dispose всем элементам списка.


han_malign   (2004-07-13 11:27:00) [43]

Что такое фрагментация памяти знаешь?

Под каждую строку выделяется блок памяти, под динамический массив, каждый раз выделяется непрерывный блок памяти, а в старую "дыру" он уже не влезает - вот и получается, что при SetLength(...,Length()+1), занимается память на 2*Length()+1(по грубым прикидкам), и это нарастает в геометрической прогрессии...


opoloXAI   (2004-07-13 11:11:00) [44]

Добрый день.
Я понял, что использовать динамические массивы, в принципе, никто не советует. Но всё-же хотелось бы для себя понять (дабы в следующий раз "не наступить на те-же грабли"), почему приведённый код на Win98 съедает 60МГбт памяти за считанные секунды?

TmySearchRec = record
   Size: Integer;
   Name: TFileName;
   Path: String;
 end;
TSameForm = class(TForm)
   DirectoryLB: TdfsSystemTreeView;
   StBar: TStatusBar;
   ItemFind: TMenuItem;
private
   { Private declarations }
   mas: array of TmySearchRec;
   kolFls: Int64;
   GetPamat: Int64; {специально, чтобы подсчитатать размер занимемой памяти}
   procedure ScanDir(StartDir: string);
   procedure AddFile(SchRec: TSearchRec; Dir: String);
 public
   { Public declarations }
 end;

var
 SameForm: TSameForm;

function  myFileSize(sz: Int64): String;
function  Okruglit(x: Real; nm:Word): String;
function  Stepen(y,x:Real): Real;

implementation

{$R *.dfm}

function  myFileSize(sz: Int64): String;
var ms: Real48;
begin
    ms:=sz;
    Result:=FloatToStr(ms)+' байт';
    ms:=ms/1024;
    If ms>=1 then Result:=Okruglit(ms,3)+' Кбайт';
    ms:=ms/1024;
    If ms>=1 then Result:=Okruglit(ms,3)+' Мбайт';
    ms:=ms/1024;
    If ms>=1 then Result:=Okruglit(ms,3)+' Гбайт';
end;

function  Okruglit(x: Real; nm:Word): String;
var s: String;
   tmp: Real;
   i,p: Word;
begin
    tmp:=Round(x*Stepen(10,nm))/Stepen(10,nm);
    s:=FloatToStr(tmp);
    p:=pos(',',s);
    If p=0 then begin
       s:=s+',';
       p:=length(s);
    end;
    For i:=1+length(s)-p to nm do s:=s+'0';
    Result:=s;
end;

function  Stepen(y,x:Real): Real;
begin
    Result:=exp(x*ln(y));
end;

procedure TSameForm.ItemFindClick(Sender: TObject);
begin
    kolFls:=0;
    SetLength(mas,kolFls);
    try ScanDir(DirectoryLB.Directory);
    except MessageDLG('Ошибка обращения к диску !',mtWarning,[mbYes],0);
    end;
end;

procedure TSameForm.ScanDir(StartDir: string);
var  SearchRec: TSearchRec;
begin
    If StartDir[Length(StartDir)]<>'\' then StartDir:=StartDir+'\';
    If FindFirst(StartDir+'*.*',faAnyFile,SearchRec)=0 then begin
repeat If (SearchRec.Attr and faDirectory)<>faDirectory then AddFile(SearchRec,StartDir)
                                                               else If (SearchRec.Name<>'..')and(SearchRec.Name<>'.') then ScanDir(StartDir+SearchRec.Name+'\');
until FindNext(SearchRec)<>0;
FindClose(SearchRec);
    end;
    StBar.Panels[2].Text:=' '+StartDir;
    StBar.Panels[1].Text:=' Найдено : '+IntToStr(kolFls)+' файла(ов)';
    StBar.Panels[0].Text:=' Память: '+myFileSize(GetPamat);
    Application.ProcessMessages;
end;

procedure TSameForm.AddFile(SchRec: TSearchRec; Dir: String);
begin
    kolFls:=kolFls+1;
    SetLength(mas,kolFls);
    mas[kolFls-1].Size:=SchRec.Size;
    mas[kolFls-1].Name:=AnsiUpperCase(SchRec.Name);
    mas[kolFls-1].Path:=Dir;
    GetPamat:=GetPamat+SizeOf(SchRec.Size)+SizeOf(SchRec.Name)+SizeOf(Dir);
end;

Результат работы таков: когда найдено 12065 файлов свободной физической памяти нет вообще (из 80МГбт возможных), а размер файла подкачки составляет 65МГбт. Я специально ввел переменную GetPamat, чтобы считать, сколько занимается на хранение данных массива. Получается 141,387Кбт. Так куда же девается память? Может я где-то забыл поставить ... .Free???
Заранее спасибо.


Sheng   (2004-07-12 13:07:00) [45]


> Тимохов ©   (12.07.04 12:29) [5]
>
> >   StrDispose(sMyMassiv^.Name);
>
> вы тут вероятно имели и виду v1 and v2?


сорри, не всё покоцал. Это я пример из проги своей тянул. Конечно же, не надо.


Тимохов   (2004-07-12 12:31:00) [46]

динамические массивы работают плохо в одном случае - если в массив добавлять много элементов вот так:
SetLength(a, length(a)+1). В этом случае каждый раз вызывается reallocmem. Лучше всего брать механизм реализованный в TList: count + capacity. Capacity просто равно текущей длинне массива. А count придется хранить отдельно. Скорость добавления возрастает многократно. По опыту добавления 100000 элементов - примерно в 100 раз.


Тимохов   (2004-07-12 12:29:00) [47]


>   StrDispose(sMyMassiv^.Name);

вы тут вероятно имели и виду v1 and v2?

зачем это?
при dispose записи строки-элементы записи будут очищены автоматически.


Sheng   (2004-07-12 12:21:00) [48]

У меня тоже были глюки с динамическими массивами. Я решил это просто - использовал стек. Скорость сразу, как говориться, на глаз раза в 4 быстрее стала, и работает устойчиво. Вот те пример кода:

PMyMassiv = ^TMyMassiv;
TMyMassiv = record
             v1: String;
             v2: String;
             v3: Integer;
             Next: PMyMassiv;
           end;

...

MyMassivFirst,MyMassiv: PMyMassiv;

дальше пишешь процедуры добавления, поиска и очистки стека:

procedure TfrmMain.AddToStack(<твои переменные для добавления> var sMyMassiv: PSongs);
begin
 if sMyMassiv=nil then New(sMyMassiv) else
   begin
     New(sMyMassiv^.Next);
     sMyMassiv:=sMyMassiv^.Next;
   end;

 sMyMassiv^.<тут присваиваешь>
 sMyMassiv^.<тут присваиваешь>
 ...

 sMyMassiv^.Next:=nil;
end;

procedure TfrmMain.KillStack(var sMyMassiv: PMyMassiv);
var
 Temp: PMyMassiv;
begin
 while sMyMassiv<>nil do
   begin
     Temp:=sMyMassiv^.Next;
     StrDispose(sMyMassiv^.Name);
     Dispose(sMyMassiv);
     sMyMassiv:=Temp;
   end;
end;

если чего не понятно - пиши


MBo   (2004-07-12 12:14:00) [49]

>Увеличиваю количество элементов массива на один
Вот здесь и собака порылась - стоит увеличивать размер на существенное число элементов. Или воспользоваться списками TList, а может, и TStringList еще удобнее будет.


Тимохов   (2004-07-12 12:14:00) [50]

"полные" тормоза у вас скорее в другом месте программы


Тимохов   (2004-07-12 12:12:00) [51]

не зная стреднюю длину строк v1 и v2 сказать что-то сложно.

если длина примерно 30 символов, то опиасанный вами массив будет занимать 400кб, что согласитесь копейки.


Страницы:   1 2 3

Наверх

Титульная страница Поиск, карта сайта Написать письмо