Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2004.12.05;
Скачать: CL | DM;

Вниз

TList и расход памяти   Найти похожие ветки 

 
Matrex   (2004-11-20 19:23) [0]

Народ, как правильно очистить запись/все записи в TList? Проблема в том что выделяя память инструкцией New для очередной записи в TList, после выполнения инструкции List.Delete(n)или List.Clear память, выделенная под записи, не высвобождается… Например попробуйте кусок кода и запустите диспетчер задач, обратите внимание на расход памяти… Или может я чего-то не понимаю? :(

Type Rtest=Record
a:Array[0..1024*10] of byte;
end;
PTest=^Rtest;

procedure TForm1.Timer1Timer(Sender: TObject);
var test:PTest;
begin
New(Test);
List.Add(Test);
List.Clear;
end;


 
Anatoly Podgoretsky ©   (2004-11-20 19:43) [1]

До очистки списка надо освободить все его элементы, сам TList про них нечего не знает.


 
Matrex   (2004-11-20 20:05) [2]

Это я понимаю типа выполнить инструкцию Dispose. А как это все вместе связать, я пробовол но что то слабо у меня получилось... Может есть идеи?


 
Anatoly Podgoretsky ©   (2004-11-20 20:34) [3]

Если все добавлялись как New, то в цикле проход по всем элементам TList и Dispose


 
jack128 ©   (2004-11-20 20:49) [4]

Конкретно для типа Rtest можно использовать вот такой класс:

 TListEx = class(TList)
 private
   FFreeMem: boolean;
 protected
   procedure Notify(Ptr: Pointer; Action: TListNotification); override;
 public
   constructor Create(AFreeMem: boolean);
   property FreeMemory: boolean read FFreeMem write FFreeMem;
 end;

constructor TListEx.Create(AFreeMem: boolean);
begin
 inherited Create;
 FFreeMem := AFreeMem;
end;

procedure TListEx.Notify(Ptr: Pointer; Action: TListNotification);
begin
 inherited;
 if (Action = lnDeleted) and FreeMemory then
   Dispose(Ptr);
end;


А вот если ты в записи будешь хранить ссылочные типы, такие как длинные строки, варианты, то перед удалением те придётся делать Finalize этих записей


 
dimaxx ©   (2004-11-20 23:29) [5]

Так правильнее (обязательно с конца в начало):

var List: TList;

for I:=pred(List.Count) downto 0 do
 begin
   Dispose(List.Items[I]);
   List.Delete(I);
 end;
List.Free;


 
Игорь Шевченко ©   (2004-11-20 23:38) [6]

Я уже несколько лет использую такой класс вместо TList в большинстве случаев:

{
  Модуль: HSObjectList

  Описание: Класс списка объектов. Уничтожает содержащиеся объекты
            при собственном разрушении,
            имеет метод очистки без уничтожения содержимого.

  Ограничения применения: Элементы списка должны быть наследниками TObject

  Автор: Игорь Шевченко

  Дата создания: 21.11.2001

  История изменений:
  10.12.2003 - В класс THSObjectList добавлено свойство Objects.
}
unit HSObjectList;

interface
uses
 Classes;

type
 THSObjectList = class(TList)
 private
   function GetObjects(I: Integer): TObject;
 public
   property Objects[I : Integer] : TObject read GetObjects;
   procedure Clear; override;
   { Очистка списка без разрушения содержимого }
   procedure RemoveAll;
 end;

implementation

{ THSObjectList }

procedure THSObjectList.Clear;
var
 I: Integer;
begin
 for I:=0 to Pred(Count) do
   Objects[I].Free;
 inherited;
end;

function THSObjectList.GetObjects(I: Integer): TObject;
begin
 Result := TObject(inherited Items[I]);
end;

procedure THSObjectList.RemoveAll;
var I : Integer;
begin
 for I:=Pred(Count) downto 0 do
   Delete(I);
end;

end.


 
jack128 ©   (2004-11-20 23:44) [7]

Игорь Шевченко ©   (20.11.04 23:38) [6]
Хм. А чем это лудше стандартного TObjectList? (это так.. Упреждающий вопрос перед наведением критики ;-) )


 
VMcL ©   (2004-11-20 23:46) [8]

>>jack128 ©  (20.11.04 20:49) [4]

Во-первых,
if (Action = lnDeleted) and FFreeMemory then
  Dispose(PTest(Ptr));


Во-вторых,
>А вот если ты в записи будешь хранить ссылочные типы, такие как длинные строки, варианты, то перед удалением те придётся делать Finalize этих записей

В случае применения Dispose процедуру Finalize вызывать не нужно.

>>Игорь Шевченко ©  (20.11.04 23:38) [6]

А чем не устраивает TObjectList?


 
Anatoly Podgoretsky ©   (2004-11-20 23:47) [9]

dimaxx ©   (20.11.04 23:29) [5]
Нет не правильнее, List.Delete(I); абсолютно лишняя строка, только съедающая время.


 
jack128 ©   (2004-11-20 23:54) [10]

VMcL ©   (20.11.04 23:46) [8]
Во-первых,
if (Action = lnDeleted) and FFreeMemory then
 Dispose(PTest(Ptr));


Так как RTest Не содержит ссылочных типпов, то не обязательно, а в общем случае, конечно надо.. Но это мой общий класс, если хочется привязать его к типу RTest, то пожалуйста, никто не мешает ;-)

VMcL ©   (20.11.04 23:46) [8]
В случае применения Dispose процедуру Finalize вызывать не нужно.

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


 
Игорь Шевченко ©   (2004-11-20 23:57) [11]


> А чем не устраивает TObjectList?


Если совсем честно, то в тот момент, когда я писал этот класс, я про TObjectList не знал :)


 
Anatoly Podgoretsky ©   (2004-11-21 00:57) [12]

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


 
Matrex   (2004-11-21 10:46) [13]

Всем огромное и человеческое спасибо, кто не остался равнодушен к моей скромной проблеме, однако не совсем понятно. Попробую на конкретном примере - делаю класс для работы с сетевым соединениями. Запись RNetFile представляет собой:


Type RFileData=record
Path,DisplayName,DisplayCreateDate,DisplayFileSize,
TypeName,FileExt:WideString;
OpenIconIndex,CloseIconIndex:Integer;
Attributes:TFIleAttributes;
CreateDate:Tdatetime;
FileSize:Longint;
end;

Type RNetFile=record
UserName, // имя пользователя
FileName:WideString; // открытый вайл
FileData:RFileData;// данные по файлу (собственная запись см. выше)
FileNameID:DWord;// идентификатор открытого файла
StatusOpen:DWord;// статус обращения
TimeBegin,TimeEnd:TDateTime;// начало соединения, конец соединения.
end;
PNetFile=^RNetFile;


периодически очищается и заполняется новыми значениями в таймере. По совету dimaxx для очистки всего списка соединений делаю:


Procedure TScanNet.DeleteList;
begin
While CountNetFile<>0 do begin
  Dispose(FNetFileList.Items[CountNetFile-1]);
  FNetFileList.Delete(CountNetFile-1);
end;
end;


Не работает :( - т.е. все равно жрет память… Делаю по совету jack128:


Procedure TScanNet.DeleteList;
begin
While CountNetFile<>0 do begin
  Dispose(FNetFileList.Items[CountNetFile-1]);
  Finalize(FNetFileList.Items[CountNetFile-1]^);
  FNetFileList.Delete(CountNetFile-1);
end;
end;


Не работает. Присяжные в шоке :( в чем проблема? Ну ни как не пойму…


 
jack128 ©   (2004-11-21 12:32) [14]

Matrex   (21.11.04 10:46) [13]
Procedure TScanNet.DeleteList;
begin
While CountNetFile<>0 do begin
 Dispose(FNetFileList.Items[CountNetFile-1]);
 Finalize(FNetFileList.Items[CountNetFile-1]^);
 FNetFileList.Delete(CountNetFile-1);
end;

Сначала Finalize, а потом Dispose ;-) Либо см совет VMcL(c)


 
VMcL ©   (2004-11-21 13:04) [15]

>>jack128 ©  (20.11.04 23:54) [10]

>если явно привести нетипизированный уккаазатель к типизированному, не нужен..

Естетсвенно. Я это даже не писал,  потому что считаю, что перед вызовом Dispose всегда следует приводить тип к корректному. Тогда потом меньше мороки, если запись нужно изменить с целью ввода какого-либо поля типа String, Dynamic Array и т. п. Хотя, в принципе, это дело вкуса.


 
Matrex   (2004-11-21 13:43) [16]

Ровным счетом ничего не миняется. Мы что то друг друга понять не можем... А вот компилятор вообще на использование Finalize выдает предупреждение, что сначала Initialize и даже некомпелирует эту строчку. Вот кусук проги:


Type RNetFile=record
UserName,
FileName:WideString;
FileNameID:DWord;
StatusOpen:DWord;
TimeBegin,TimeEnd:TDateTime;
end;
PNetFile=^RNetFile;

Procedure TForm1.Clear;
begin
While List.Count<>0 do begin
 Finalize(List.Items[List.Count-1]^);
 Dispose(List.Items[List.Count-1]);
 List.Delete(List.Count-1);
end;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
var test:PNetFIle;
   r:integer;
begin
for r:=1 to 100 do begin
  New(Test);
  Test^.UserName:="Александр";
  Test^.FileName:="C:\Download.html";
  Test^.FileNameID:=34;
  Test^.StatusOpen:=99;
  List.Add(Test);
end;
Clear;
end;


Где ошибка, тыкните пальцем, или я скоро с ума сойду :)


 
Matrex   (2004-11-21 14:07) [17]

А вот она :) Все всем спасибо.

 Dispose(PNetFIle(List.Items[List.Count-1]));


 
dimaxx ©   (2004-11-22 00:54) [18]

2 Anatoly Podgoretsky: Почему лишняя?


 
jack128 ©   (2004-11-22 01:53) [19]

dimaxx ©   (22.11.04 0:54) [18]
Да все нормально.. Этот код будет даже быстрее(не на много, но быстрее) работать, чем
for I:=pred(List.Count) downto 0 do
 Dispose(List.Items[I]);
List.Free;

Matrex   (21.11.04 14:07) [17]
Ты не понимаешь, что делает процедура Finalize. Вызывать её следует так: Finalize(PTest(List.Items[List.Count-1])^);   Эта процедура освобождает тамять из под строк, дин массивов, объявленных в этой записи, так что естественно, что нужно  приводить НЕ типизированный указатель листа к нужному типизированому указателю, что компилятор мог построить код файнализации.



Страницы: 1 вся ветка

Текущий архив: 2004.12.05;
Скачать: CL | DM;

Наверх




Память: 0.52 MB
Время: 0.056 c
14-1100759845
syte_ser78
2004-11-18 09:37
2004.12.05
проверка скорости ввода пароля


4-1096510724
The-13th-Angel
2004-09-30 06:18
2004.12.05
Как отследить изменение реестра и копирование файлов


1-1101324267
BuG
2004-11-24 22:24
2004.12.05
TEdit и TWebBrowser


14-1100536294
kaZaNoVa
2004-11-15 19:31
2004.12.05
Психологические вирусы ?


9-1091703940
Evgeniy_K
2004-08-05 15:05
2004.12.05
OOP and DD