Страница 1 из 2

Правильное уничтожение созданных в рантайме объектов?

СообщениеДобавлено: 13.07.2012 10:16:10
OberonAR
День добрый!
Подскажите по сабжу пожалуйста. Конкретный пример.
1) У меня в проекте есть функция (прописана в отдельном модуле) получения значения поля из определенной таблицы бд MySQL. Внутри нее я создаю
Код: Выделить всё
var query : TZReadOnlyQuery;
begin

query:=TZReadOnlyQuery.Create(application);
query.Connection:=DataModule1.ZConnection1;
.
.
.
{уничтожаю так:}
query.Close;

query:=nil;
query.Free;
end;


Функция эта вызывается довольно много раз. И каждый раз после ее вызова я наблюдаю в диспетчере процессов как мое приложение отхапывает себе кусок памяти 300-1000 кб и не освобождает ее. Подозреваю что уничтожаю query неправильно.

Re: Правильное уничтожение созданных в рантайме объектов?

СообщениеДобавлено: 13.07.2012 10:35:52
Mr.Smart
Код: Выделить всё
query:=nil;
query.Free;

:?: :?: :?:
Если вы загляните в метод Free, то увидите следующее:
Код: Выделить всё
      procedure TObject.Free;

        begin
           // the call via self avoids a warning
           if self<>nil then
             self.destroy;
        end;

после ваших действий query:=nil; Self равен nil и уничтожение объекта не происходит.
Выкиньте нафиг строчку с query:=nil;!!!

з.ы. Интересно узнать, кто вас научил так уничтожать объекты?

Re: Правильное уничтожение созданных в рантайме объектов?

СообщениеДобавлено: 13.07.2012 10:48:20
Brainenjii
По теме - лучше будет, наверное, так -
Код: Выделить всё
var query : TZReadOnlyQuery;
begin

query:=TZReadOnlyQuery.Create(application);
query.Connection:=DataModule1.ZConnection1;
.
.
.
{уничтожаю так:}
query.Close;

FreeAndNil(query);
end;

Не по теме - зачем такая штука как Free? Только же прятать ошибки в алгоритме - пытаться уничтожить отсутствующий объект это же явная ошибка. А если напрямую Destroy'ем - хоть сразу исключение поднимается...
Просто я всегда вызываю деструктор напрямую - может я допускаю какую-то ошибку и чего-то не знаю?

Re: Правильное уничтожение созданных в рантайме объектов?

СообщениеДобавлено: 13.07.2012 10:50:41
SSerge
Mr.Smart писал(а):з.ы. Интересно узнать, кто вас научил так уничтожать объекты?


это копипаста с JAVA/C#, там принято присваивать указателю на экземпляр null, якобы это заставляет шевелиться сборщик мусора и объект уничтожать.

Re: Правильное уничтожение созданных в рантайме объектов?

СообщениеДобавлено: 13.07.2012 11:01:23
Sergei I. Gorelkin
Brainenjii писал(а):Просто я всегда вызываю деструктор напрямую - может я допускаю какую-то ошибку и чего-то не знаю?


Например, при возникновении исключения в конструкторе деструктор вызывается для недосозданного объекта, если у этого объекта есть поля-объекты, то они могут быть равны nil.

Re: Правильное уничтожение созданных в рантайме объектов?

СообщениеДобавлено: 13.07.2012 11:18:08
Brainenjii
хм... Не знал, что при исключении в конструкторе неявно вызывается деструктор. Или я Вас не правильно понял и Вы просто об освобождении "недосозданного" объекта?... Вообще, стараюсь не допускать возможности поднятия исключений на этапе инициализации. Кроме этого - есть ли ещё какие-то ситуации, когда вызов Destroy напрямую "хуже" Free?
В любом случае, ИМХО, если есть сомнения, то лучше проверить - был ли создан объект перед его разрушением явно. К тому же, Free допускает только одно имя у деструктора, хотя, к счастью, в паскале давать имена конструкторам/деструкторам можно произвольные ^_^

Re: Правильное уничтожение созданных в рантайме объектов?

СообщениеДобавлено: 13.07.2012 11:44:34
Sergei I. Gorelkin
Все правильно поняли, деструктор вызывается неявно при исключении в конструкторе (и до кучи, в методе AfterConstruction).

Re: Правильное уничтожение созданных в рантайме объектов?

СообщениеДобавлено: 13.07.2012 12:18:37
debi12345
По-параноидальному, с перестраховками (также на случай аварийного выхода программы,..):

Код: Выделить всё
result:= OK;
QueryVar:= nil;
try
  QueryVar:= QueryType.Create(..);
  try
    [...]
    QueryVar.Active:= true;
  except
    on e:EDatabaseError do begin
       result:= FAILED;
       ShowMessage('Smth wrong');
       exit;
    end;
    [..]
  end;
finally
  if QueryVar <> nil then begin
    QueryVar.Active:= false;
    FreeAndNil(QueryVar);
  end;
end;

Re: Правильное уничтожение созданных в рантайме объектов?

СообщениеДобавлено: 14.07.2012 09:47:35
OberonAR
FreeAndNil(Query) вызывает исключение доступа к памяти... Хотя вчера вечером FreeAndNil(Query) работало без исключений, но и память не освобождало. Ничего не пойму.
Вот вчерашний вариант функции, который сегодня вызывает исключение:
Код: Выделить всё
function get_value_from_bd (table : integer; id : string; pole : string) : string;
var query : TZReadOnlyQuery; s1,s2 : string;
begin
if id='' then id:='0';

query:=TZReadOnlyQuery.Create(application);


query.Connection:=DataModule1.ZConnection1;


query.SQL.Clear;
query.SQL.Add('SELECT s_tables.`table`, s_tables.id_table FROM s_tables WHERE s_tables.id_s_tables = '+inttostr(table));
query.Open;
s1:=query.FieldByName('table').AsString;
s2:=query.FieldByName('id_table').AsString;
query.Close;

query.SQL.Clear;
query.SQL.Add('SELECT '+s1+'.'+pole+' FROM '+s1+' WHERE '+s1+'.'+s2+' = '+id);
query.Open;

get_value_from_bd:=query.FieldByName(pole).AsString;

query.Close;



Query.Active:= false;
FreeAndNil(Query);

end;                           


с просто query.free работает, но тоже не освобождает память...

Дополнение.
В этом же модуле есть другая ф-я, которая создает заранее подготовленную форму (из автосоздания убрана) и также создает TZQuery как и выше описано. что форму, что query удаляю FreeAndNil("имя переменной"). Так вот в этой ф-ии все работает без исключений, но опять же не освобождается память.

Добавлено спустя 39 минут 39 секунд:
OberonAR писал(а):с просто query.free работает, но тоже не освобождает память...


не, не работает, на любую попытку free ошибка доступа. Блин, ну вчера же работало без исключений. Ничего не понимяю :cry:

Re: Правильное уничтожение созданных в рантайме объектов?

СообщениеДобавлено: 14.07.2012 15:02:33
debi12345
FreeAndNil(Query) вызывает исключение доступа к памяти

Перед его вызовом желательно проверять переменную на "<> nil".

с просто query.free работает, но тоже не освобождает память...

Пишите багрепорт по поводу MEMORY LEAK команде ZEOS.

Re: Правильное уничтожение созданных в рантайме объектов?

СообщениеДобавлено: 14.07.2012 15:28:28
OberonAR
debi12345 писал(а): с просто query.free работает, но тоже не освобождает память...


Пишите багрепорт по поводу MEMORY LEAK команде ZEOS.


Нет, не работает query.free, я ошибся. с TForm работает и FreeAndNil даже память очищает, но только пытаешься сделать FreeAndNil для переменной TZQuery (ZEOS), сразу исключение...

Может это у меня какие настройки слетели?

Re: Правильное уничтожение созданных в рантайме объектов?

СообщениеДобавлено: 14.07.2012 16:23:40
debi12345
но только пытаешься сделать FreeAndNil для переменной TZQuery (ZEOS),

на NIL перед FREE проверяете ?

Добавлено спустя 1 минуту 30 секунд:
Код: Выделить всё
сразу исключение...

Или все же фатальный сбой типа AcessViolation или SegmentainFault ?

Re: Правильное уничтожение созданных в рантайме объектов?

СообщениеДобавлено: 14.07.2012 17:23:59
OberonAR
debi12345 писал(а):Или все же фатальный сбой типа AcessViolation или SegmentainFault ?


AcessViolation
правда на nil не проверял в этот раз.

Re: Правильное уничтожение созданных в рантайме объектов?

СообщениеДобавлено: 14.07.2012 18:18:56
debi12345
правда на nil не проверял в этот раз.

Почему ?
Никогда не помешает перед созданием экзмепляра объекта присвоить объектной перремнной NIL, а перед освобождением экземпляра - проверить объектную переменную на NIL. Это убережет от фатальных ошибок, связанных с несозданием объекта (если такое возможно в принципе - ошибки в коде создания, нехватка памяти,..).

Re: Правильное уничтожение созданных в рантайме объектов?

СообщениеДобавлено: 14.07.2012 19:04:56
alexey38
Судя по всему исключение при уничтожении самого объекта (попробуйте посмотреть в отладчике, шагнув внутрь).
А функция Free и так проверяет на NIL перед Destroy, см. самое первое сообщение, где было вначале присоваивание NIL а потом FREE, и была только утечка памяти.