delphi - Delphi中接口(interface)的内存管理

标签 delphi memory-management interface access-violation

我正在努力学习来自 C# 的 delphi 和内存管理。

这种斗争的当前体现是,当我用完这些元素时,我不知道如何处理它们。从阅读和我的实验来看,如果我有一个被转换为接口(interface)的对象,那么我唯一的选择是将引用设置为 nil。 如果我去打电话 FreeAndNil() 我最终遇到了访问冲突,例如:

var
  foo: IFoo;
begin
  foo := TFoo.Create();
  FreeandNil(foo);
end;

当然,我需要做的就是改变 foo:IFoo;到 foo:TFoo;它很高兴。或者简单地将指针设置为 nil,而不是调用 freeandNil。

foo := nil;

所以,在某种程度上,我根本不明白反病毒在哪里。

在不同的层面上,我想编写代码,使其不需要知道它是接口(interface)还是对象。我希望能够以相同的方式编写所有内存管理,但我似乎无法编写可以处理类或接口(interface)的方法。好吧,那不是真的,我确实有一些东西,但它太丑了,我犹豫是否要发布它。

但我想我也应该问,其他人在做什么?在心里记住什么是接口(interface)并且只是将这些指针置零?否则调用 FreeAndNil?

我第一次想将事情作为一个具体的类来实现,但是当我发现代码可以通过两种不同的方式来完成某些工作时,我会回来将其更改为接口(interface)。我不想浏览代码并改变它处理该引用的方式,这是我当时最不想做的事情。

但为了讨论,我最好的(几乎唯一)想法是这个类:

interface

type
  TMemory = class(TObject)
  class procedure Free(item: TObject); overload; static;
  class procedure Free<T: IInterface>(item: T); overload; static;
  end;

implementation

uses
  System.SysUtils;

  { TMemory }

class procedure TMemory.Free(item: TObject);
begin
  FreeandNil(item);
end;

class procedure TMemory.Free<T>(item: T);
begin
  //don't do anything, it is up the caller to always nil after calling.
end;

然后我就可以持续调用:

TMemory.Free(Thing);
Thing := nil;

测试代码:

procedure TDoSomething.MyWorker;
var
  foo: IFoo;
  fooAsClass: TFoo;
  JustAnObject: TObject;
begin
  foo := TFoo.Create();
  fooAsClass := TFoo.Create();
  JustAnObject := TObject.Create();

  TMemory.Free(foo);
  foo := nil;

  TMemory.Free(fooAsClass);
  fooAsClass := nil;

  TMemory.Free(JustAnObject);
  JustAnObject := nil;
end;

运行时没有泄漏或访问违规。 (使用 MadExcept)

非常感谢 Delphi 社区。你们是最好的学习者!

最佳答案

访问冲突的原因是 FreeAndNil 采用非类型化参数,但期望它是一个东西。所以该方法对对象进行操作。

procedure FreeAndNil(var Obj);
var
  Temp: TObject;
begin
  Temp := TObject(Obj); //Obj must be a TObject otherwise all bets are off
  Pointer(Obj) := nil; //Will throw an AV if memory violation is detected
  Temp.Free; //Will throw an AV if memory violation is detected
end;

如果您销毁先前已销毁或从未创建的对象,则可能会检测到上述内存违规(注意不保证)。如果 Obj 根本不引用任何对象,而是引用其他对象(例如接口(interface)、记录、Integer,因为它们没有实现 Free),也可能会被检测到如果他们这样做了,它的定位方式将不会与 TObject.Free 相同)。

On a differently level, I want to write the code such that it does not need to know if it is an interface or an object. I want to be able to write all of my memory management the same exact way.

这就像说您想以与使用淋浴完全相同的方式使用汽车。
好吧,也许差异并没有那么极端。但关键是接口(interface)和对象(以及就此而言的记录)使用不同内存管理范式。您无法以同样的方式管理他们的内存。

  • 对象需要显式销毁。您可以使用所有权模型,但销毁仍然是一个明确的外部操作。
  • 接口(interface)采用引用计数。编译器注入(inject)代码来跟踪引用(查看)底层实例的字段和变量的数量。通常,当释放最后一个引用时,对象会自行销毁。 (有一些方法超出了这个答案的范围来改变这一点。)

关于delphi - Delphi中接口(interface)的内存管理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43792357/

相关文章:

interface - GraphQL 接口(interface) : [interface] expects "fieldname" but [type] does not provide it

c# - 通用接口(interface)的通用列表不允许,任何替代方法?

delphi - Delphi 中除 DUnit 之外的最佳单元测试工具

delphi - 在 Delphi 2009 中显示 PDF 文件的最佳方式是什么

delphi - 如何知道应用程序是否空闲

c++ - 在 C++ 中重用内存

delphi - 更改Delphi OpenDialog的目录

php - 我如何判断我的 php 脚本用完了多少内存/资源?

Android Monitor 显示我的应用程序内存不断增加

java - 接口(interface)的默认方法可以用来描述行为吗?