【问题标题】:Destroying COM object in Delphi在 Delphi 中销毁 COM 对象
【发布时间】:2011-09-22 11:36:46
【问题描述】:

有一些 .net 程序集,通过 COM 在 delphi 中调用它。

var
   intf: ITest;

...
   intf:= CreateComObject(CLASS_TEST) as ITest;
   ...
   //here comes some stuff
   ...

我必须做些什么来破坏它以释放内存。还是不行?

【问题讨论】:

    标签: .net delphi com


    【解决方案1】:

    COM 对象是引用计数的,当引用计数达到零时它们会自动销毁。每当您的代码添加或删除对象的引用时,编译器都会自动添加对_AddRef 和_Release 接口方法的调用。将引用 COM 对象的变量设置为nil 将调用_Release(减少引用计数),并且如果引用计数达到零,该对象也会被释放(如果引用计数不为零,则不会释放)。当变量超出范围时(即局部变量,过程退出时),如果变量引用 COM 对象(或任何引用计数的 Delphi 接口),编译器还将调用 _Release。

    【讨论】:

      【解决方案2】:

      你最好释放内存

             intf := nil;
      

      当你不再需要它时。如果intf 被定义为fIntf,即作为类属性,则最好使用try...finally intf := nil; 块,或者在Destroy 覆盖方法中。

      如果intf 定义在堆栈上,它会在方法结束时自动释放。编译器生成了一个隐藏的try...finally intf := nil; end 块来释放intf 实例。

      【讨论】:

      • 我不熟悉delphi。你说'在堆栈上定义'是什么意思,每个变量都定义在 var 部分,所以它们都在堆栈上?
      • 是的,它在堆栈中。所以Delphi会在方法结束时释放这个引用。如果 intf 存储在对象字段中,它将在对象销毁期间释放它。
      • 附注当我说“释放”时,我并不坚持要销毁引用的对象,它的行为取决于它是如何设计的。 p.p.s.当你想尽快释放对象时,需要为接口引用分配 nil,即如果你想控制释放的顺序。
      • -1 因为您“应该”释放内存是不正确的。这是完全可选的。
      • @Fred 我写了“应该”,因为我发现,例如,一些 Delphi 编译器(而不是旧的,我说的是 Delphi 2010)do not produce the code they had too for object,即使他们“应该“并且有记录这样做......因此,我不能 100% 确定它会一直如此。如果您如此自信并且接口从未发生过此类问题,我很高兴。当然,我知道object 已被弃用,接口也不是... ;)
      【解决方案3】:

      所有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 分配给持有该接口的变量。请注意,这当然是假设该接口没有其他引用。

      【讨论】:

        【解决方案4】:

        对象自动释放。但是,如果您明确想要释放 intf 变量持有的引用,您可以将其设置为 nil。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-05-12
          • 2012-11-03
          • 1970-01-01
          • 2021-12-03
          • 2015-10-19
          • 2017-01-11
          相关资源
          最近更新 更多