为了提供尽可能多的信息,这是我正在做的非常基本的示例
type
IMyInterface = interface
[THE_GUID_HERE]
// some methods
end;
TMyInterfaceArray = Array of IMyInterface;
TMyInterfacedObject = class(TInterfacedObject, IMyInterface)
// implementation of the Interface etc. here
end;
TContainingObject = class
private
FIObjectArray: TMyInterfaceArray;
public
constructor Create;
destructor Destroy; override;
procedure NewInstanceOfInterfacedObject;
end;
implementation
constructor TContainingObject.Create;
begin
inherited;
// Just to illustrate that an Instance is being created...
NewInstanceOfInterfacedObject;
end;
destructor TContainingObject.Destroy;
var
I: Integer;
begin
for I := Low(FIObjectArray) to High(FIObjectArray) do
FIObjectArray[I] := nil;
SetLength(FIObjectArray, 0); // Array collapsed
inherited;
end;
procedure TContainingObject.NewInstanceOfInterfacedObject;
var
LIndex: Integer;
begin
LIndex := Length(FIObjectArray);
SetLength(FIObjectArray, LIndex + 1);
FIObjectArray[LIndex] := TMyInterfacedObject.Create;
end;
好的,因此创建了
TContainingObject
的实例,然后又创建了TMyInterfacedObject
的实例,并将其存储在IMyInterface
数组中。调用
TContainingObject
的destructor
时,它是零引用,并且折叠Array。我的问题是,在没有其他引用的情况下,从未调用
TMyInterfacedObject
的destructor
,从而导致内存泄漏。我是在做错什么,还是Delphi的引用计数系统不能应付接口类型数组中保存的接口对象的简单概念?
感谢您的任何建议!
更多信息
TContainingObject
提供Array属性以访问Array中包含的IMyInterface
的各个实例。在我的实际代码中,多个接口类型之间都有循环引用。
我们建议
IMyInterface
包含函数GetSomething: IAnotherInterface
,而IAnotherInterface
包含GetMyInterface: IMyInterface
(循环引用)。这可能引起我的问题吗?如果是这样,则绝对需要循环引用,那么考虑到该解决方案将会是什么?
最佳答案
如果IMyInterface
的实现包含一个IAnotherInterface
成员,并且IAnotherInterface
的实现包含一个IMyInterface
成员,并且它们相互引用,那么除非您清除,否则它们的引用计数将永远无法降至0。引用之一,这可能意味着向您的接口添加方法来做到这一点,例如:
type
IAnotherInterface = interface;
IMyInterface = interface
['{guid}']
function GetAnotherInterface: IAnotherInterface;
procedure SetAnotherInterface(Value: IAnotherInterface);
property AnotherInterface: IAnotherInterface read GetAnotherInterface write SetAnotherInterface;
end;
IAnotherInterface = interface
['{guid}']
function GetMyInterface: IMyInterface;
procedure SetMyInterface(Value: IMyInterface);
property MyInterface: IMyInterface read GetMyInterface write SetMyInterface;
end;
。
type
TMyInterface = class(TInterfacedObject, IMyInterface)
private
FAnotherInterface: IAnotherInterface;
public
function GetAnotherInterface: IAnotherInterface;
procedure SetAnotherInterface(Value: IAnotherInterface);
end;
TAnotherInterface = class(TInterfacedObject, IAnotherInterface)
private
FMyInterface: IMyInterface;
public
function GetMyInterface: IMyInterface;
procedure SetMyInterface(Value: IMyInterface);
end;
function TMyInterface.GetAnotherInterface;
begin
Result := FAnotherInterface;
end;
procedure TMyInterface.SetAnotherInterface(Value: IAnotherInterface);
begin
if FAnotherInterface <> Value then
begin
if FAnotherInterface <> nil then FAnotherInterface.SetMyInterface(nil);
FAnotherInterface := Value;
if FAnotherInterface <> nil then FAnotherInterface.SetMyInterface(Self);
end;
end;
function TAnotherInterface.GetMyInterface: IMyInterface;
begin
Result := FMyInterface;
end;
procedure TAnotherInterface.SetMyInterface(Value: IMyInterface);
begin
if FMyInterface <> Value then
begin
if FMyInterface <> nil then FMyInterface.SetAnotherInterface(nil);
FMyInterface := Value;
if FMyInterface <> nil then FMyInterface.SetAnotherInterface(Self);
end;
end;
现在,当您没有明确释放其中一个引用时,请查看引用计数:
var
I: IMyInterface;
J: IAnotherInterface;
begin
I := TMyInterface.Create; // I.RefCnt becomes 1
J := TAnotherInterface.Create; // J.RefCnt becomes 1
I.AnotherInterface := J; // I.RefCnt becomes 2, J.RefCnt becomes 2
...
{
// implicit when scope is cleared:
I := nil; // I.RefCnt becomes 1, I is NOT freed
J := nil; // J.RefCnt becomes 1, J is NOT freed
}
end;
现在将显式发行版添加到引用之一:
var
I: IMyInterface;
J: IAnotherInterface;
begin
I := TMyInterface.Create; // I.RefCnt becomes 1
J := TAnotherInterface.Create; // J.RefCnt becomes 1
I.AnotherInterface := J; // I.RefCnt becomes 2, J.RefCnt becomes 2
...
I.AnotherInterface := nil; // I.RefCnt becomes 1, J.RefCnt becomes 1
{
// implicit when scope is cleared:
I := nil; // I.RefCnt becomes 0, I is freed
J := nil; // J.RefCnt becomes 0, J is freed
}
end;
。
var
I: IMyInterface;
J: IAnotherInterface;
begin
I := TMyInterface.Create; // I.RefCnt becomes 1
J := TAnotherInterface.Create; // J.RefCnt becomes 1
I.AnotherInterface := J; // I.RefCnt becomes 2, J.RefCnt becomes 2
J := nil; // I.RefCnt still 2, J.RefCnt becomes 1, J is NOT freed yet
...
I.AnotherInterface := nil; // I.RefCnt becomes 1, J.RefCnt becomes 0, J is freed
{
// implicit when scope is cleared:
I := nil; // I.RefCnt becomes 0, I is freed
}
end;
关于arrays - 在数组中保存时释放接口(interface)对象的问题,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/9985394/