Форум: "Основная";
Текущий архив: 2004.05.02;
Скачать: [xml.tar.bz2];
ВнизКак корректно освободить память, занятую записями из TList? Найти похожие ветки
← →
Курдль © (2004-04-14 12:03) [0]Вопрос, на первый взгляд, простой. Однако...
type
recJump = record
Date: TDateTime;
Value: Integer;
end;
ptrJump = ^recJump;
procerure Сonjunction;
var P: ptrJump; List: TList;
begin
List := TList.Create;
try
New(P);
...
List.Add(P);
...
finally
освобождение
List.Free;
end;
end;
Как бы вы реализовали это самое освобождение?
← →
Skier © (2004-04-14 12:06) [1]в цикле
Dispose(List.Items[I]);
← →
clickmaker © (2004-04-14 12:07) [2]Для ленивых - TObjectList с OwnsObjects = true и заменить record на class
а так в цикле Dispose(P)
← →
Курдль © (2004-04-14 12:10) [3]Ок! А если я передумаю фрикать лист, а решу с ним поработать повторно "с чистого листа"?
← →
Skier © (2004-04-14 12:10) [4]>clickmaker © (14.04.04 12:07) [2]
> а так в цикле Dispose(P)
Да ну ? :)
← →
VMcL © (2004-04-14 12:32) [5]>>Курдль © (14.04.04 12:03)
Обычно пишется наследник TList и перекрывается метод Notify.
← →
Курдль © (2004-04-14 12:33) [6]
> Обычно пишется наследник TList и перекрывается метод Notify.
...и прменяется метод Delete, наверное. Так?
← →
VMcL © (2004-04-14 13:02) [7]>>Курдль © (14.04.04 12:33) [6]
>и прменяется метод Delete, наверное
Нет.
Вот пример того, как обычно делаю я:PMyRec = ^TMyRec;
TMyRec = record
Test: Integer;
end;
TMyList = class(TList)
protected
procedure Notify(Ptr: Pointer; Action: TListNotification); override;
public
function New: PMyRec; // новая функция для выделения памяти
end;
implementation
{ TMyList }
function TMyList.New: PMyRec;
begin
Result := AllocMem(SizeOf(Result^));
end;
procedure TMyList.Notify(Ptr: Pointer; Action: TListNotification);
begin
inherited Notify(Ptr, Action); // в D6 необязательно, TList.Notify пустой
if Ptr <> nil then
FreeMem(Ptr);
end;
← →
VMcL © (2004-04-14 13:05) [8]Ну и соответсвенно твой кусок кода будет выглядеть как-то так:
begin
List := TMyList.Create;
try
P := List.New;
// Заполнение структуры P^
// ...
List.Add(P);
finally
List.Free;
end;
end;
← →
Тимохов © (2004-04-14 13:09) [9]Знаю, что Skier © будет не рад, но все же рискну его дополнить:
писать Dispose(List.Items[I]) можно только в том случае, когда в записи нет динамических элементов (длинных строк, дин массивов, интерфейсов), т.е. как в данном случае. Если они есть то нужно писать так:
var
p: ptrJump
begin
for ...
begin
p := List[i]
dispose(p).
end;
end;
иначе будет утечка.
ЗЫ. Анатолий, ну согласитесь вы наконец :)))
← →
Skier © (2004-04-14 13:12) [10]
> иначе будет утечка.
не будет
← →
VMcL © (2004-04-14 13:16) [11]>>Тимохов © (14.04.04 13:09) [9]
Вообще-то, если есть "длинные" строки, дин. массивы и т. п., то НУЖНО вызвать Finalize перед освободением памяти с помощью таких процедур, как FreeMem. В случае же с Dispose это не нужно (см. help по Finalize).
← →
Тимохов © (2004-04-14 13:27) [12]
> VMcL © (14.04.04 13:16) [11]
Не очень понятно, что вы хотите мне сказать? Что предыдущий оратор прав?
Поясняю для всех!
Вызов dispose(list.items[i])
эквивалентен:
mov edx,[ebp-$18]
mov eax,[ebp-$14]
call TList.Get
xor edx,edx
call @FreeMem
т.е. фактически работа идет через freemem - поэтому никаких finalize нет.
Вызов P := List.items[i]; dispose(p)
равен
mov edx,[ebp-$18]
mov eax,[ebp-$14]
call TList.Get
mov [ebp-$0c],eax
mov edx,[$00456b24]
mov eax,[ebp-$0c]
call @Dispose
Вызов @Dispose все видят?
← →
Курдль © (2004-04-14 13:44) [13]Таким образом конструкция
for i := 0 to List.Count - 1 do
Dispose(List[i])ж
оказывается ущербной по отношению к
for i := 0 to List.Count - 1 do
begin
P := List[i];
Dispose(P);
end;
Правильно я понимаю ход ваших мыслей?
← →
Тимохов © (2004-04-14 14:20) [14]
> Курдль © (14.04.04 13:44) [13]
Уточнение к примеру. Правильно я понимаю, что во втором случае через P, P - типизированный указатель, т.е. не просто pointer, а P: PRec, где PRec = ^TRec; TRec = record ... end; ?
Если да, то ответ такой:
первая конструкция является ущербной в случае если запись, содержит ansistring, array of или interface. Если этих типов не содержится, то оба примера нормально будут работать.
Если же P это просто Pointer, то оба примера являются одинаково ущербными.
← →
Курдль © (2004-04-14 14:26) [15]
> Если же P это просто Pointer, то оба примера являются одинаково
> ущербными.
А кому нужен список "просто Pointer-ов"? :)
У меня ж в 1-м посте все расписано!
← →
Тимохов © (2004-04-14 14:31) [16]
> Курдль © (14.04.04 14:26) [15]
если p имеет тип из 1, то ответ на вопрос в 13 такой - используйте второй метод.
хотя замечу, что в вашем случае разницы нет. разница будет если вы в запись добавите строку, только тогда искать утечку будет сложнее...
← →
Курдль © (2004-04-14 14:34) [17]Ок! Спасибо!
А то я подзабыл уже, откуда у всякого-такого ноги растут.
Особо забавно было глянуть родную реализацию TList.Clear.
← →
VMcL © (2004-04-14 14:41) [18]>>Тимохов © (14.04.04 13:27) [12]
Да, верно. Dispose должен знать точный тип объекта, поэтому нужно просто явно указать тип:
Dispose(ptrJump(List.Items[I]));
← →
panov © (2004-04-14 14:44) [19]еще раз.
В какой же момент происходит утечка памяти?
← →
Тимохов © (2004-04-14 14:48) [20]
> VMcL © (14.04.04 14:41) [18]
Ура, радость - хоть один светлый со мной согласился :)))))
Я обычно через переменную делаю. Наверное и так можно.
> panov © (14.04.04 14:44) [19]
dipose(list[i]) совобождает память из под записи (т.к. фактически вызывается freemem для памяти из list[i]), но не осовобожадает память занятую строками. Последнее происходит т.к. не вызывается finalize. Действительно, если подумать откуда дельфи знать какая реально с труктура лежит по этому адресу. Все что знает менеджер памяти - столько занято память. Ее он и освобождает. За это должен отвечать программист - сказать dipose что вообще освобождается и какая у освобождаемой области структура.
Страницы: 1 вся ветка
Форум: "Основная";
Текущий архив: 2004.05.02;
Скачать: [xml.tar.bz2];
Память: 0.49 MB
Время: 0.034 c