【发布时间】:2011-09-22 11:36:46
【问题描述】:
有一些 .net 程序集,通过 COM 在 delphi 中调用它。
var
intf: ITest;
...
intf:= CreateComObject(CLASS_TEST) as ITest;
...
//here comes some stuff
...
我必须做些什么来破坏它以释放内存。还是不行?
【问题讨论】:
有一些 .net 程序集,通过 COM 在 delphi 中调用它。
var
intf: ITest;
...
intf:= CreateComObject(CLASS_TEST) as ITest;
...
//here comes some stuff
...
我必须做些什么来破坏它以释放内存。还是不行?
【问题讨论】:
COM 对象是引用计数的,当引用计数达到零时它们会自动销毁。每当您的代码添加或删除对象的引用时,编译器都会自动添加对_AddRef 和_Release 接口方法的调用。将引用 COM 对象的变量设置为nil 将调用_Release(减少引用计数),并且如果引用计数达到零,该对象也会被释放(如果引用计数不为零,则不会释放)。当变量超出范围时(即局部变量,过程退出时),如果变量引用 COM 对象(或任何引用计数的 Delphi 接口),编译器还将调用 _Release。
【讨论】:
你最好释放内存
intf := nil;
当你不再需要它时。如果intf 被定义为fIntf,即作为类属性,则最好使用try...finally intf := nil; 块,或者在Destroy 覆盖方法中。
如果intf 定义在堆栈上,它会在方法结束时自动释放。编译器生成了一个隐藏的try...finally intf := nil; end 块来释放intf 实例。
【讨论】:
object,即使他们“应该“并且有记录这样做......因此,我不能 100% 确定它会一直如此。如果您如此自信并且接口从未发生过此类问题,我很高兴。当然,我知道object 已被弃用,接口也不是... ;)
所有COM接口都必须实现IUnknown:
IUnknown = interface
function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
end;
IUnknown 提供两种服务。首先,QueryInterface 允许客户端获取对象可能实现的其他接口。第二个服务是生命周期管理。
每次引用 COM 对象时,您都有责任调用_AddRef。每次您放弃对 COM 对象的引用时,您都会被约定调用_Release。
_AddRef 和 _Release 的规范实现是让实现对象维护一个引用计数变量,该变量在引用被获取和释放时递增和递减。如果对 _Release 的调用将此引用计数设置为 0,则该对象会自行销毁。
接口的 Delphi 实现代表您管理对 _AddRef 和 _Release 的调用。当您分配给接口变量时,编译器会发出以下代码:
_Release,如果它确实之前确实引用了某些东西。_AddRef。编译器还安排在变量离开作用域时调用_Release。
这意味着您无需采取任何特殊措施来确保您的 COM 对象将被销毁。当对象的最后一个引用离开作用域时,它们自然会被销毁。
但是,如果您确实希望提前销毁一个对象,那么您只需将nil 分配给持有该接口的变量。请注意,这当然是假设该接口没有其他引用。
【讨论】:
对象自动释放。但是,如果您明确想要释放 intf 变量持有的引用,您可以将其设置为 nil。
【讨论】: