Текущий архив: 2005.07.11;
Скачать: CL | DM;
ВнизПочему есть утечка памяти при использовании интерфейсов? Найти похожие ветки
← →
Суслик © (2005-06-24 12:59) [0]Есть два метода
procedure Dummy1(const aI: IInterface);
begin
// некая операция с aI
end;
procedure Dummy2(aI: IInterface);
begin
// некая операция с aI
end;
При вызове Dummy1(TInterfaceObject.Create()) происходит утечка памяти т.к. не отрабатывает деструктор созданного объекта TInterfaceObject.
При вызове Dummy2(TInterfaceObject.Create()) все ок - деструктор отрабатывает корректно.
Это глюк delphi или мой?
← →
Digitman © (2005-06-24 13:03) [1]
> Это глюк delphi или мой?
ни твой ни Делфи.
это - ФИЧА (а не баг и не "глюк")
при
const aI: IЧегоТоТам
инкремента интерф.ссылки НЕ происходит,
а при
< aI: IЧегоТоТам
происходит
← →
Суслик © (2005-06-24 13:04) [2]
> [1] Digitman © (24.06.05 13:03)
Да это понятно, что фича (cpu я тоже смотреть умею). Только:
1. она нигде не описана
2. она изрядно гадит жизнь (
← →
Digitman © (2005-06-24 13:10) [3]
> она нигде не описана
описана.
в справке просто покопаться следует изрядно детальней ... ибо прямой ссылки нет ...
> она изрядно гадит жизнь
ой не ври)
достаточно знать и понимать, что при передаче по const Делфи-компайлер НЕ ответственен за работу со сч-ком ссылок, в то время как во 2-м упомянутом варианте делфи-компайлер вставляет неявный код инкремента (и, если требуется, - декремента) упомянутого сч-ка интерфейсной ссылки
попросту говоря, при const никаких неявных _addref, _release нет, в то время как в упомянутом ином случае они фигурируют (и вполне оправданно)
← →
default © (2005-06-24 13:21) [4]Суслик © (24.06.05 13:04) [2]
совершенно логично действует компилятор...
← →
Digitman © (2005-06-24 13:31) [5]
> Суслик
а есть ведь еще вариант с
var Intf: IМойИнтерфейс
странно что ты не присовокупил его к вопросу, ибо так же концептуален он
← →
Суслик © (2005-06-24 14:01) [6]
> [5] Digitman © (24.06.05 13:31)
такой вариант работает, есно я это проверил.
В справке про const скорее всего это есть. Но ... читай дальше
----------
... про логичность я бы не стал соглашаться.
Т.к. фактически объект будучи созданным выходит из scope и если дельфи декларирует подсчет ссылок, то это ее дело уничтожать интрефейсы. А то, что я сам решил при передаче в метод не делать подсчет ссылок, это дельфи волновать вообще говоря мало должно - его задача обеспечивать live scope (если уж дельфи за это взялся).
← →
Digitman © (2005-06-24 14:15) [7]
> А то, что я сам решил при передаче в метод не делать подсчет
> ссылок, это дельфи волновать вообще говоря мало должно
совершенно верно.
и именно поэтому ты в ДАННОМ случае передаешь свой интерфейс как параметр как const-параметр.... и компилятор при этом НЕ делает никаких неведомых тебе "телодвижений", т.е. все что ты понаписал - полностью прогнозируемо и подконтрольно тебе.
← →
Суслик © (2005-06-24 14:25) [8]убрали бы они вообще нафиг из delphi подсчет ссылок, либо сделали нормальный garbage collection для интерфейсов. Все лучше было бы.
← →
Игорь Шевченко © (2005-06-24 14:29) [9]Суслик © (24.06.05 14:25) [8]
> либо сделали нормальный garbage collection для интерфейсов.
Java или C# тебе в руки.
← →
Digitman © (2005-06-24 14:30) [10]
> Суслик © (24.06.05 14:25) [8]
> бы они вообще нафиг из delphi подсчет ссылок, либо сделали
> нормальный garbage collection для интерфейсов
а вот тут ты уже начал ужасную чушь пороть)
остановись, вникни, подумай над сабжем !
просмотри, к примеру, sconnect.pas ... остынь) ...
все в этом плане закономерно и правильно !
)
← →
Digitman © (2005-06-24 14:32) [11]
> garbage collection для интерфейсов
галиматья полная.
что значит "сборка мусора для интерфейсов" ?
НЕТ в списке существующих где-то там интерфейсов МУСОРА !
← →
Суслик © (2005-06-24 14:37) [12]
> [11] Digitman © (24.06.05 14:32)
ладно, давай без всяких там слов "галиматься" и пр.
------------
что будет здесь (ответь не пробуя, только честно)?procedure e;
begin
TInterfacedObject.Create();
end;
← →
Digitman © (2005-06-24 14:48) [13]
> что будет здесь (ответь не пробуя, только честно)?
конкретно здесь (т.е. при вызове ДАННОЙ процедуры откуда бы то ни было) будет утечка.
тут и "пробовать" ничего не нужно - ты создал объект - экземпляр класса - потерял его адрес в памяти и уничтожить впоследствии, не имея адреса, разумеется не можешь.
класс объекта в дан.случае совершенно неважен.
← →
Суслик © (2005-06-24 14:50) [14]
> [10] Digitman © (24.06.05 14:30)
> просмотри, к примеру, sconnect.pas ... остынь) ...
Ну да, они все делают через дополнительную локальную переменную:function TDataBlockInterpreter.CallGetServerList: OleVariant;
var
Flags: TVarFlags;
Data: IDataBlock;
begin
Data := TDataBlock.Create as IDataBlock;
Data.Signature := CallSig or asGetAppServers;
Data := FSendDataBlock.Send(Data, True);
Result := ReadVariant(Flags, Data);
end;
А, кстати, насчет того, что сборка мусора здесь ни при чем я с трудом могу с тобой согласиться. Зачем сделан посчет ссылок? (если не ошибаюсь в ++ его нет). Для того, чтобы было удобно. Но по факту получается так, что приходится помнить условия, при которых подсчет работает верно. Приведенный мной пример не единственный.
← →
Суслик © (2005-06-24 14:52) [15]
> [13] Digitman © (24.06.05 14:48)
Согласен, это я что-то налажал :)
← →
Суслик © (2005-06-24 14:57) [16]
> [13] Digitman © (24.06.05 14:48)
Ладно, закрыто.
Просто запомню, что в данном случае нужно быть осторожней с const.
← →
Digitman © (2005-06-24 15:03) [17]
> Ну да, они все делают через дополнительную локальную переменную
врешь)
цитирую :function TStreamedConnection.Send(const Data: IDataBlock; WaitForResult: Boolean): IDataBlock;
var
Msg: TMsg;
Context: Integer;
begin
if FSupportCallbacks then
begin
if not Assigned(FTransport) then Exit;
Data._AddRef;
PostThreadMessage(FTransport.ThreadID, THREAD_SENDSTREAM, Ord(WaitForResult),
Integer(Pointer(Data)));
...
> насчет того, что сборка мусора здесь ни при чем я с трудом
> могу с тобой согласиться. Зачем сделан посчет ссылок?
КАКОЕ отношение имеет механизм подсчета интерф.ссылок к т.н. "сборке мусора" ?
изложи свое вИденье ...
> Для того, чтобы было удобно
Да, конечно.
Мне, к примеру, неудобно, объявив в п/программе лок.переменную MyInterface типа ISomeInterface, заботиться о разрушении объекта, на который в ходе работы моей п/программы эта переменная ВОЗМОЖНО будет ссылаться. а возможно и НЕ будет.
И я с полным пониманием происходящего доверяюсь компилятору, который в ДАННОМ случае вставит неявный код
MyInterface := nil
который , если ссылка <> nil, вызовет за меня, лентяя, метод ISomeInterface._Release, что приведет к разрушению интерф.объекта, если декремент сч-ка в этот момент приведет к нулевому его значению.
← →
Суслик © (2005-06-24 15:06) [18]
> [17] Digitman © (24.06.05 15:03)
Речь была про ВЫЗЫВАЮЩУЮ сторону. Я тебе ее процитировал. Т.е. если я не хочу, чтобы у меня в исходном примере были ошибки, то я должен делать также как они.
← →
Digitman © (2005-06-24 15:19) [19]
> Суслик © (24.06.05 15:06) [18]
> Речь была про ВЫЗЫВАЮЩУЮ сторону
ок.
вызывающая сторона, зная прототип ф-ции с неким интерфейсным параметром (IUnknown или его произвольным наследником) в том или ином виде, обязана иметь четкое представление о том как поступит компилятор.
в случае const или var компилятор НЕ генерирует неявного кода вызова методов _AddRef, _Release передаваемого интерф.объекта
в противном случае компилятор генерирует неявный вызов _AddRef в контексте "открывающего" п/программу оператора begin и неявный вызов _Release в контексте "закрывающего" п/программу оператора end
Страницы: 1 вся ветка
Текущий архив: 2005.07.11;
Скачать: CL | DM;
Память: 0.5 MB
Время: 0.049 c