如果一切都实现了接口,这会是垃圾收集吗?

时间:2009-09-17 00:29:14

标签: delphi interface

我还是一个新手,我知道我的想法不正确;我只是不知道在哪里 ......

Delphi中的所有内容都来自TObject。如果所有内容都来自实现某些简单接口的TInterfaceObject(例如,“INamable”,使用返回类名称字符串的单个方法),该怎么办?由于TObject已经有一个返回名称字符串的属性,因此您无需向其他类添加任何内容。

换句话说,TInterfacedObject将从TObject(或层次结构中的高处)继承,并且当前从TObject继承的所有内容现在将从此新类继承。这是不是意味着现在一切都被引用了?

如果你能发现我缺乏知识的地方,我很乐意学习。谢谢,一如既往 - Al C.

5 个答案:

答案 0 :(得分:8)

目前尚不清楚你是否在问:

  • 为什么Borland最初开发Delphi时没有这样做?
  • 为什么Embarcadero在未来的Delphi版本中没有这样做?
  • 为什么我不使用自己的用户数据类型?
  

这是否意味着现在所有内容都被引用?

是的,它会。

但是,您不一定要重新计算所有:每个小整数,每个字符串,每个布尔值,数组中的每个元素......如果没有其他原因, ref-counting的实现增加了一些开销,例如每个对象有一点额外的内存,对于大型对象来说可能是微不足道的,但如果应用于每个微小的对象,则会更加显着。

另请参阅Garbage Collector For Delphi Objects and Components,其中(引用),

Delphi提供三种对象管理方式:

  
      
  1. 使用try..finally创建/销毁对象。
  2.   
  3. 使用TComponent后代 - 创建一个组件并让其所有者释放它。
  4.   
  5. 接口 - 当接口的引用计数变为0时   实现它的对象是   破坏。
  6.         

    德尔福帮助说你不应该混在一起   TComponent所有者的方法与   接口内存管理,但......

         

    这会是垃圾收集吗?

不完全;仅仅引用计数不如垃圾收集那么健壮:

  • 使用引用计数,如果您有两个引用计数实例,每个实例持有对另一个的引用,则它们不会自动释放。要释放它们,你需要打破这个“循环引用”(即明确告诉其中一个释放它对另一个的引用)。

  • 通过真正的垃圾收集,垃圾收集器会注意到这两个因素并未从其他任何地方引用,并将它们两者都释放。

<强>更新
如果您将可能的循环引用注释为[weak]引用,那么它们将被销毁。但在Delphi 10.1 Berlin之前,这只适用于NexGen编译器(即那些使用LLVM的编译器)。从10.1柏林开始,这些[weak]引用随处可见。

答案 1 :(得分:5)

它不会工作垃圾收集,因为接口使用一个非常简单的引用计数系统,并且在Delphi代码中非常常见的循环引用打破了简单的引用计数。

答案 2 :(得分:3)

不,因为有两件事:

  1. 即使一个类实现了一个接口,它也不会自动使它被引用计数。只有当您实际使用它来实现该接口时,引用计数才会有效。
  2. 正如其他人已经说过的那样:接口中的引用计数将导致在引用计数达到0时立即释放类实例。这是在代码中对该方法的Free方法的隐式调用。这将失败,例如如果两个对象互相引用。真正的垃圾收集将释放对象,而不是当它们超出范围但需要内存时,因此每次引用计数达到0时都不会影响性能,因为对象将继续存在。此外,一个好的垃圾收集器将检测隔离的循环引用(例如A引用B引用C引用A但没有其他引用任何这些对象)并且还将释放这些对象。

答案 3 :(得分:2)

垃圾收集与简单的引用计数不同。当ref计数达到0时,您可以自动删除,但这也不是垃圾回收。垃圾收集意味着放弃控制何时从内存中删除内容的能力,并允许底层语言的实现来优化behviours。您不再关注引用计数,并且信任特定垃圾收集实现的动态行为。

当然,垃圾收集使用引用计数系统来知道何时不再引用某些内容,但这只是一小部分难题。

答案 4 :(得分:1)

引用计数是垃圾收集的一种形式,但不是很好。它被一些语言(我认为是python)使用,尽管经常使用循环检测。

即使您来自TInterfaceObject,该对象也不会被引用计数,因此除非您只使用接口引用而不是对象引用,否则将收集垃圾。

即。你需要使用

Var 
  nameable: IMyInterface;
begin
  nameable:= IMyInterface.Create();
  nameable.x(y);
  etc
end;

这意味着您的界面需要支持您需要的方法和属性,这需要为每个类创建一个接口,这很快就会变得乏味。

虽然可以在D2009或更晚的时候合理地完成。见巴里凯利对smart pointers的暗示。通常的引用countng cavets适用。