【问题标题】:Whats the difference in terms of memory usage (clean up, etc) of Delphi Interface and C# interfacesDelphi接口和C#接口的内存使用(清理等)有什么区别
【发布时间】:2011-03-07 01:20:32
【问题描述】:

我是一名 Delphi 程序员,并试图在此处使用 C# 完成一些工作。 C# 中的接口是否以与 Delphi 中相同的方式工作 - 您不必担心释放它,因为它会在超出范围时被释放。

【问题讨论】:

  • C罗,你是专门问接口还是参考?
  • 我在询问接口 - 因为 Delphi 处理它的方式,我即将构建一些东西并热衷于使用接口,但缺乏对幕后发生的事情的了解。
  • 那部分现在应该清楚了(-:

标签: c# delphi interface


【解决方案1】:

Delphi 和 .NET 在这方面的主要区别(特别是与接口相关)是清理的不确定性。

在 Delphi 中,所有接口的使用都遵循 COM 模型。也就是说,它是引用计数的。如果该类实现了引用计数生命周期管理模型,那么当引用计数降至零时,对象实例将在该点销毁。

注意:生命周期管理是类实现的一个功能。为了更清楚地看到这一点,看看 TInterfacedObject 中 IUnknown.Release 的实现:

function TInterfacedObject._Release: Integer;
begin
  Result := InterlockedDecrement(FRefCount);
  if Result = 0 then
    Destroy;
end;

如果 Release 的实现没有调用 Destroy,那么当引用计数下降到零时对象不会被销毁,并且仍然必须显式地释放' d 通过一些对象引用该对象。这可以在 Delphi 中用于创建实现接口但不受自动引用计数生命周期管理的对象(尽管您无法避免编译器注入的引用计数代码,即调用 AddRef 和发布)。

在 .NET 中,首先没有引用计数本身。垃圾收集器的工作方式要复杂得多,其细节与本次讨论没有直接关系。

主要区别在于,当一个对象不再被使用时(然而,这是在一个简单的引用计数之外确定的),这不是它在 .NET 中被销毁的点。

事实上,从理论上讲,未使用的对象可能会在您的应用程序中累积,直到您的进程生命周期的更晚点——尤其是在空闲周期很少的计算密集型应用程序中。在 .NET 中,您根本无法准确地确定何时这些未使用的对象最终将被释放。

有些人会争辩说这是一件好事,尽管它混淆了清理对象被销毁时锁定或拥有的资源的通常做法,因为您通常需要释放那些比等待垃圾收集器更紧急地锁定/拥有资源。这就是 IDisposable 在 .NET 中的用武之地,其中的细节再次不直接相关,您可以在闲暇时进一步研究。

【讨论】:

  • 感谢您的精彩解释 - 您的回答和 Henk 的回答对我帮助很大。
【解决方案2】:

是的,对于程序员来说,它们看起来是一样的。使用并忘记。

在内部,它们的工作方式不同,在 .NET 中,接口是(只是另一个)由垃圾收集器清除的引用。

在 Delphi 中,接口是一种特殊的引用计数(一种不同的内存管理技术)。

.NET/Delphi 的主要区别在于 .NET所有 引用(接口、对象和数组)都是垃圾回收的。

【讨论】:

  • 感谢您的解释。可以说,如果我让我的对象实现 IDisposable 并使用类似“using (MyClass myobj = new MyClass()){} 我可以实现类似于 Delphi 所做的事情(超出范围,你就完成了) ) 而不是等待垃圾收集器?
  • @罗纳尔多:是的,有点。但是你通常不应该这样做。 IDisposable 用于管理资源(FileHandles),而不是内存。您无法控制对象的生命周期,但您也不必担心。
【解决方案3】:

我认为它在超出范围时不会被释放,但是当垃圾收集发生时(当它们不再使用时)

【讨论】:

  • 实际上正确但难以解读:Delphi 是什么行为,.NET 是什么?
【解决方案4】:

c# 中的所有内容都是垃圾回收的,因此您无需手动释放它们。

但存在显着差异。 Delphi 接口是引用计数的,c# 接口是垃圾收集的。 C# 支持多接口继承。

【讨论】:

  • Delphi 也支持多接口继承,没有区别。
  • C# 和 Delphi 都支持多个接口实现,这肯定是真的吗? “多接口继承”可能表明接口“A”可以从多个接口“B”和“C”继承,这在 Delphi 或 C# 中不可能。当然,如果一个类实现了多个接口,那么任何派生/后代类都会“继承”这些多个接口,但在我看来,这是具有实现继承和实现多个接口的能力的附带副作用,并不构成多个接口继承“特性”。
  • @Deltics:请注意 interface IFoo : IBar, IDisposable 是可以的,但是当您将其反射回来时,实现 IFoo 的类可能会出现 3 个不相关的接口。
  • @Henk:感谢您提供的链接。对我来说似乎是毫无意义的语法糖......从多个接口“继承”在语义和功能上等同于要求实现多个接口(如果实现了一个指定的“多个派生”接口)。即,它是实现接口契约的一种有用方式,但它不是 OO 中通常意味着的“继承”,并且您的反射器观察似乎证实了这一点 - 它是“看起来像”继承的语法糖,但不是不是真的。至少,恕我直言。
  • @Deltics:我不同意,这是有道理的。就像IFoo f = ...; Ibar b = f; 每个 IFoo 都是 IBar 一样。替代原则起作用。
【解决方案5】:

内存管理由 CLR 处理。垃圾收集是 CLR 中的一项内在服务。

您无需将变量或字段清空即可让垃圾收集器收集对象。

您不需要实现或使用 IDisposable 来清理内存。 Dispose 方法对释放内存中的托管对象没有任何作用。 Dispose 方法应该用于释放“非托管”资源,包括数据库连接、位图或您可能持有的任何非托管结构。

如果您在讨论可视化组件(表单、对话框等)中的界面,这会变得更加混乱。在 WinForms 中,我相信当一个界面(视觉)不再可见时,它会被清理并收集垃圾。需要时会重新创建表单。在 WPF 中,Windows 和 Pages 不会立即销毁。除非应用程序开发人员专门清理它们,否则它们会在应用程序的生命周期内被缓存。这提高了 WPF 应用程序的性能,但增加了担心应用程序资源的额外负担。

垃圾收集是一个完全独立的话题。托管对象从物理内存中的实际释放发生在这里,完全取决于垃圾收集服务,您通常不必担心这是如何工作的。

干杯

【讨论】:

  • -1 表示“您不需要取消...”短语。变量为真,字段为假。
  • 对于其余部分,这缺乏任何 Delph 视角。
  • 当类超出范围时,字段被清理。为什么需要清空字段?如果您的类持有非托管资源,则需要在 Dispose 方法实现中清理这些资源。清除该字段并不一定会清理非托管资源。问题还与 C# 中的内存管理有关。我错过了 Delphi 接口和 C# 接口之间的显式链接,但不觉得它有损于我的贡献。
  • 您可能需要清空包含对对象的引用的字段,以使对象成为可收集的。我现在看到了您的其他解释,但这没有任何意义-没有语言可以让您清除 var/fields。并且接口都不包含
猜你喜欢
  • 2019-10-16
  • 2018-01-06
  • 2019-10-05
  • 2012-03-24
  • 2014-04-03
  • 1970-01-01
  • 1970-01-01
  • 2011-01-25
  • 2016-04-24
相关资源
最近更新 更多