Утечка подсчёта ссылок в интерфейсах !BUG!

Вопросы программирования на Free Pascal, использования компилятора и утилит.

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

Ответить
Аватара пользователя
hinst
энтузиаст
Сообщения: 781
Зарегистрирован: 12.04.2008 18:32:38

Утечка подсчёта ссылок в интерфейсах !BUG!

Сообщение hinst »

Написал тест-программу для тестирования подсчёта ссылок в интерфейсах.
:shock: :shock: :shock:

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

program project1;

uses
  SysUtils;

type
  IFace = interface
  end;

  { TFace }

  TFace = class(TInterfacedObject, IFace)
  public
    function QueryInterface(constref iid : tguid;out obj) : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
    function _AddRef : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
    function _Release : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF};
    destructor Destroy; override;
  end;

{ TFace }

function TFace.QueryInterface(constref iid: tguid; out obj): longint; stdcall;
begin
  result := QueryInterface(iid, obj);
end;

function TFace._AddRef: longint; stdcall;
begin
  result := inherited _AddRef;
  WriteLN('+REFER =' + IntToStr(RefCount));
end;

function TFace._Release: longint; stdcall;
begin
  WriteLN('-DEREF =' + IntToStr(RefCount - 1));
  result := inherited _Release;
end;

destructor TFace.Destroy;
begin
  WriteLN('Intface object destroyed');
  inherited Destroy;
end;

function CreateFace: IFace; stdcall;
begin
  result := TFace.Create;
end;

var
  face: IFace;

begin
  face := CreateFace;
  face := nil;
  WriteLN('Reaching end.');
end.

Выводит вот что:

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

+REFER =1
+REFER =2
-DEREF =1
Reaching end.
-DEREF =0
Intface object destroyed

Почему, спрашивается, интерфейс освобождается только уже после того, как ему присвоили nil ???? Это какая-то утечка подсчёта ссылок.
Я почему-то убеждён, что он должен писать сообщение об освобождении до того, как напишет Reaching end.
FPC 2.6.0
Помогите. что мне с этим делать
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
Сообщения: 1409
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

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

Помимо явно объявленной переменной, интерфейс может иметь произвольное количество ссылок во временных переменных, на усмотрение компилятора. Это не является багом.

Программы не должны зависеть от значения счетчика ссылок.
Аватара пользователя
hinst
энтузиаст
Сообщения: 781
Зарегистрирован: 12.04.2008 18:32:38

Сообщение hinst »

ну класс. Вот у меня интерфейс загружается из DLL, надо перед выходом из программы FreeLibrary делать, а из-за того, что счётчик не обнулился, программа валится.
DLL уже освободилась, указатели на все методы интерфейса указывают в никуда, а тут прога начинает вызывать _Release
Так что, интерфейс нельзя принудительно освободить? вообще никак что ли?
Аватара пользователя
Vapaamies
постоялец
Сообщения: 292
Зарегистрирован: 24.07.2012 22:37:59
Откуда: Санкт-Петербург
Контактная информация:

Сообщение Vapaamies »

hinst писал(а):Так что, интерфейс нельзя принудительно освободить? вообще никак что ли?

Присвоить nil. Это штатно. Если на интерфейс нет других ссылок, он освободится.
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
Сообщения: 1409
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

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

Дык не нужно делать FreeLibrary библиотеке, из которой используются интерфейсы. Ведь не просто так в виндовых COM-библиотеках есть процедура DllCanUnloadNow.

ps: Delphi на приведенном примере ведет себя точно также.
Аватара пользователя
hinst
энтузиаст
Сообщения: 781
Зарегистрирован: 12.04.2008 18:32:38

Сообщение hinst »

Всё разобрался. Если кому интересно, там проблема в том, что компилятор может держать временные не очевидные ссылки на интерфейсы до выхода из области видимости. В общем если вынести всю работу с интерфейсами в отдельную процедуру, то только тогда можно быть уверенным что после её завершения ссылок не останется. Короче, я хз, как объяснить, вот тема по которой сделал:
http://stackoverflow.com/questions/6745 ... olevariant
Ответить