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

Вниз

Как корректно освободить память, занятую записями из 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;
Скачать: CL | DM;

Наверх




Память: 0.52 MB
Время: 0.025 c
14-1081239306
Slaga
2004-04-06 12:15
2004.05.02
RTFM


9-1068383106
G A M E R
2003-11-09 16:05
2004.05.02
LOD


6-1079013081
webmaster
2004-03-11 16:51
2004.05.02
Список групп, и расшареные папочки..


11-1065696703
Aser
2003-10-09 14:51
2004.05.02
Кириллица в sqlitecc


1-1082013300
Тимохов
2004-04-15 11:15
2004.05.02
MakeObjectInstance