Форум: "Основная";
Текущий архив: 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