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

Общие вопросы программирования, алгоритмы и т.п.

Модератор: Модераторы

Аватара пользователя
OberonAR
новенький
Сообщения: 73
Зарегистрирован: 08.02.2012 11:46:04
Откуда: Краснодарский край

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

Сообщение 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 неправильно.
Mr.Smart
долгожитель
Сообщения: 1796
Зарегистрирован: 29.03.2008 00:01:11
Откуда: из леса!

Сообщение 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;!!!

з.ы. Интересно узнать, кто вас научил так уничтожать объекты?
Аватара пользователя
Brainenjii
энтузиаст
Сообщения: 1351
Зарегистрирован: 10.05.2007 00:04:46

Сообщение Brainenjii »

По теме - лучше будет, наверное, так -

Код: Выделить всё

var query : TZReadOnlyQuery;
begin

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

FreeAndNil(query);
end;

Не по теме - зачем такая штука как Free? Только же прятать ошибки в алгоритме - пытаться уничтожить отсутствующий объект это же явная ошибка. А если напрямую Destroy'ем - хоть сразу исключение поднимается...
Просто я всегда вызываю деструктор напрямую - может я допускаю какую-то ошибку и чего-то не знаю?
SSerge
энтузиаст
Сообщения: 971
Зарегистрирован: 12.01.2012 05:34:14
Откуда: Барнаул

Сообщение SSerge »

Mr.Smart писал(а):з.ы. Интересно узнать, кто вас научил так уничтожать объекты?


это копипаста с JAVA/C#, там принято присваивать указателю на экземпляр null, якобы это заставляет шевелиться сборщик мусора и объект уничтожать.
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
Сообщения: 1409
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Сообщение Sergei I. Gorelkin »

Brainenjii писал(а):Просто я всегда вызываю деструктор напрямую - может я допускаю какую-то ошибку и чего-то не знаю?


Например, при возникновении исключения в конструкторе деструктор вызывается для недосозданного объекта, если у этого объекта есть поля-объекты, то они могут быть равны nil.
Аватара пользователя
Brainenjii
энтузиаст
Сообщения: 1351
Зарегистрирован: 10.05.2007 00:04:46

Сообщение Brainenjii »

хм... Не знал, что при исключении в конструкторе неявно вызывается деструктор. Или я Вас не правильно понял и Вы просто об освобождении "недосозданного" объекта?... Вообще, стараюсь не допускать возможности поднятия исключений на этапе инициализации. Кроме этого - есть ли ещё какие-то ситуации, когда вызов Destroy напрямую "хуже" Free?
В любом случае, ИМХО, если есть сомнения, то лучше проверить - был ли создан объект перед его разрушением явно. К тому же, Free допускает только одно имя у деструктора, хотя, к счастью, в паскале давать имена конструкторам/деструкторам можно произвольные ^_^
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
Сообщения: 1409
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Сообщение Sergei I. Gorelkin »

Все правильно поняли, деструктор вызывается неявно при исключении в конструкторе (и до кучи, в методе AfterConstruction).
Аватара пользователя
debi12345
долгожитель
Сообщения: 5761
Зарегистрирован: 10.05.2006 23:41:15
Откуда: Ташкент (Узбекистан)

Сообщение 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;
Аватара пользователя
OberonAR
новенький
Сообщения: 73
Зарегистрирован: 08.02.2012 11:46:04
Откуда: Краснодарский край

Сообщение 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:
Аватара пользователя
debi12345
долгожитель
Сообщения: 5761
Зарегистрирован: 10.05.2006 23:41:15
Откуда: Ташкент (Узбекистан)

Сообщение debi12345 »

FreeAndNil(Query) вызывает исключение доступа к памяти

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

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

Пишите багрепорт по поводу MEMORY LEAK команде ZEOS.
Аватара пользователя
OberonAR
новенький
Сообщения: 73
Зарегистрирован: 08.02.2012 11:46:04
Откуда: Краснодарский край

Сообщение OberonAR »

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


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


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

Может это у меня какие настройки слетели?
Аватара пользователя
debi12345
долгожитель
Сообщения: 5761
Зарегистрирован: 10.05.2006 23:41:15
Откуда: Ташкент (Узбекистан)

Сообщение debi12345 »

но только пытаешься сделать FreeAndNil для переменной TZQuery (ZEOS),

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

Добавлено спустя 1 минуту 30 секунд:

Код: Выделить всё

сразу исключение...

Или все же фатальный сбой типа AcessViolation или SegmentainFault ?
Аватара пользователя
OberonAR
новенький
Сообщения: 73
Зарегистрирован: 08.02.2012 11:46:04
Откуда: Краснодарский край

Сообщение OberonAR »

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


AcessViolation
правда на nil не проверял в этот раз.
Аватара пользователя
debi12345
долгожитель
Сообщения: 5761
Зарегистрирован: 10.05.2006 23:41:15
Откуда: Ташкент (Узбекистан)

Сообщение debi12345 »

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

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

Сообщение alexey38 »

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