Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 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.5 MB
Время: 0.033 c
6-1078395276
pai
2004-03-04 13:14
2004.05.02
Indy, IdTCPClient.writebuffer


9-1069269231
Sacred
2003-11-19 22:13
2004.05.02
Нужен совет по выделению фигуры в GLScene.


14-1081333588
syte_ser78
2004-04-07 14:26
2004.05.02
Аська


1-1082092101
guest_Dmitry
2004-04-16 09:08
2004.05.02
Подскажите компонент


1-1082229051
[BAD]Angel
2004-04-17 23:10
2004.05.02
PopUpMenu





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский