gpt4 book ai didi

delphi - 为什么子类中的接口(interface)没有释放

转载 作者:行者123 更新时间:2023-12-03 19:50:00 27 4
gpt4 key购买 nike

我面临以下情况,我想知道这段代码正在泄漏内存。
假设我有以下接口(interface)和实现:

type
ITools = interface
function HelloWorld : String;
end;

IDatabase = interface
function Query(AQuery : String) : String;
end;

IManager = interface
procedure Execute;
end;

TDatabase = class(TInterfacedObject, IDatabase)
strict private
FTools : ITools;
public
constructor Create;
destructor Destroy; override;
function Query(AQuery : String) : String;
end;

TTools = class(TInterfacedObject, ITools)
strict private
FDatabase : IDatabase;
public
constructor Create(ADatabase : IDatabase);
destructor Destroy; override;
function HelloWorld : String;
end;

TManager = class(TInterfacedObject, IManager)
strict private
FDatabase : IDatabase;
public
constructor Create;
procedure Execute;
end;

现在,如果您创建例如:
procedure Example;
var
lExample : IManager;
begin
lExample := TManager.Create;
lExample.Execute;
lExampe := nil; // Should not be necessary
end;

在哪里 FDatabase来自 TManager创建为 TDatabase并传入 TTools 的构造函数,因此它在 TTools 中与在 TManager 中具有相同的 (?) 对象/接口(interface)。
然后 lExample由于子类( IDatabase )中的接口(interface)/对象而泄漏内存。为什么不发布接口(interface)?或者我对德尔福基础知识有什么不了解?

最佳答案

Why isn't it the interface released?



你有一个循环引用。
TDatabase 包含对 TTools 的引用,而 TTools 包含对 TDatabase 的引用。
因为 Delphi 没有垃圾收集器,它无法在没有帮助的情况下解析这些循环引用。

如果您使用的是 Mobile NexGen 编译器或 D10.1 Berlin,则解决方案是将 TDatabase 声明为:
TDatabase = class(TInterfacedObject, IDatabase)
strict private
[weak] <<--
FTools : ITools;
public
constructor Create;
destructor Destroy; override;
function Query(AQuery : String) : String;
end;
[weak] FTools 时属性会触发 Delphi 生成不同的代码被安排了。并且运行时将保留一些簿记,以便即使接口(interface)的引用计数变为零,如果弱引用碰巧没有参与循环引用,对象也不会被破坏。
Marco Cantù 在这里写到: http://blog.marcocantu.com/blog/2016-april-weak-unsafe-interface-references.html
他还写了 [unsafe]属性。不要使用那个,除非您确切知道它的含义,否则它不是您需要的。

您应该只将其中一个循环引用标记为 [weak] !如果你标记这两种不幸都会发生。

编译器不支持怎么办[weak] ?
如果您在 Windows 或 OSX 目标上使用较旧的 Delphi,则解决方案如下。

按照以下说明使用此 hack: http://blog.dummzeuch.de/2014/06/19/weak-references-or-why-you-should-enable-reportmemoryleaksonshutdown/

    procedure SetWeak(_InterfaceField: PIInterface; const _Value: IInterface);    begin      PPointer(_InterfaceField)^ := Pointer(_Value);    end;    type      TChild = class(TInterfacedObject, IChild)      private        FParent: IParent; // This must be a weak reference!      public        constructor Create(Parent: IParent);        destructor Destroy; override;      end;    constructor TChild.Create(Parent: IParent);    begin      inherited Create;      SetWeak(@FParent, Parent);    end;    destructor TChild.Destroy;    begin      SetWeak(@FParent, Nil);      inherited;    end;


这样做是以一种不正当的方式进行引用,以使引用计数不会永久增加。
并不是说这个 hack 没有完全保护 [weak]属性给出。
如果您的弱引用发生在 不是 参与循环引用,那么您可能会过早破坏 FParent。

Arnaud Bouchez 在他的博客中有更详细的文章;我建议您阅读: http://blog.synopse.info/post/2012/06/18/Circular-reference-and-zeroing-weak-pointers

关于delphi - 为什么子类中的接口(interface)没有释放,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37761421/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com