Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2004.12.05;
Скачать: [xml.tar.bz2];

Вниз

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;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.5 MB
Время: 0.039 c
3-1099979637
Explorer
2004-11-09 08:53
2004.12.05
AdoDataSet для работы c StoredProc


1-1100690198
ALEKCEY
2004-11-17 14:16
2004.12.05
Обработка математического выражиния


1-1101300025
Pretender
2004-11-24 15:40
2004.12.05
Подсчет символов


1-1101031606
InfMag
2004-11-21 13:06
2004.12.05
Как убрать из окна, которое слево от трея мою прогу?


4-1098188002
sapsi
2004-10-19 16:13
2004.12.05
Переключение между приложениями





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский