Firemonkey for Windows下的Delphi ARC

Firemonkey for Windows下的Delphi ARC,delphi,automatic-ref-counting,Delphi,Automatic Ref Counting,我正在看Marco谈论自动参考计数的视频。我已经知道在Android和iOS(Firemonkey)下,我的对象是ref计数的,所以我不需要try finally块 参考计数实现是否根据平台(VLC或FMX)或操作系统工作 我的意思是: var a: TObject; begin a := TObject.Create; a.use1; a.use2; end; 这在Firemonkey中很好,如果它运行在Android/iOS/Mac上,我没有内存泄漏。但是如果我在Windows下运行

我正在看Marco谈论自动参考计数的视频。我已经知道在Android和iOS(Firemonkey)下,我的对象是ref计数的,所以我不需要
try finally

参考计数实现是否根据平台(VLC或FMX)或操作系统工作

我的意思是:

var a: TObject;
begin
 a := TObject.Create;
 a.use1;
 a.use2;
end;
这在Firemonkey中很好,如果它运行在Android/iOS/Mac上,我没有内存泄漏。但是如果我在Windows下运行这个程序(我使用了Firemonkey),我是否仍然会因为没有引用计数而导致内存泄漏


无论如何,从视频中我了解到,调用
Free
try finally
,即使在ARC下,也不是很好的用法,但它只是无用的。

ARC是根据操作系统平台实现的,而不是GUI框架

Android、iOS和Linux编译器对对象使用ARC内存管理。Windows和OSX编译器使用经典的手动内存管理,其中仅在接口引用上支持ARC,而不支持对象

VCL是一个仅限Windows的框架,它仅在经典编译器下运行

另一方面,FMX作为一个跨平台的框架,使用不同的内存管理系统,这取决于它运行在哪个操作系统平台上


try…finally Free
块在ARC编译器上确实是无用的(在结合
Free
方法发布安全防护对象的上下文中)。 但是,如果您编写的跨平台代码必须在两种内存管理系统下都能工作,则必须使用
try…finally
Free

另一方面,如果您编写的代码只能在ARC下工作,则可以安全地忽略
try…finally
Free

但是,在ARC上,您可能希望使用
Free
(在ARC编译器上,它转换为
nil
赋值),或者如果您需要在某个点释放对象,在对象的引用超出范围之前,直接将
nil
赋值给对象/接口引用


上述规则有一个重要的例外-
TComponent
子体(包括Firemonkey GUI组件和控件),其中
try…finally Free
块必须替换为
try…finally DisposeOf
,如果您要在代码中创建和释放这些实例

你可以在


这里需要注意的重要事项是:
DisposeOf
有非常特殊的用途,它不是打破参考循环和释放ARC下对象的通用解决方案。在任何地方盲目使用它都可能导致内存泄漏。更详细的答案可以在上面的Q/A中找到,在处置陷阱下

参考计数弧在delphi下是非常混乱的,它使开发变得更加困难,因为它的设计很糟糕(在delphi下)

首先,它是在RTL中构建的,与String非常相似。它可以在平台(firemonkey)和操作系统(仅在android/ios/unix上工作)上工作。因此,如果您想构建多平台代码,并且目标也是窗口(最有可能,至少只是为了调试代码)您无论如何都需要保持try。。。最后结束(是的,我说的是你,非常糟糕的设计)。所以,忘记你没有.free的例子吧,除非你想在mobile下调试(祝你好运,每次编译3分钟,这根本不可能)

注意:为了使您的代码尽可能兼容,一个好的获取规则是用.free by.dispeof替换所有您的.free by.dispeof,后跟nil
,因为在mobile下,free是一个无操作的操作,您的对象不会被销毁,并且可以在非常意外的时间被销毁(或者在最坏的情况下永远不会被销毁,如果您使用例如TTask,这种情况很常见)。这些情况并不少见,尤其是如果您经常使用匿名过程(引用过程)来创建对对象的后台捕获

始终记住,循环ref非常容易满足,并且 难以察觉

你还必须知道(你没有问,但我扩展了一点答案),他们是delphi Tobject、java对象、IOS objective C对象和接口。所有这些都有自己的规则,让每个人都感到困惑,最终没有人真正知道它是如何工作的(是的,ARC设计糟糕的一部分也是它带来的困惑),即使是emb开发人员在他们的delphi源代码中也犯了错误,看看这个问题的例子:这很简单,但没有任何答案

圆弧和Objective-C包裹对象

Delphi NextGen编译器实现自动引用计数(ARC)对于所有Delphi对象。编译器将为您管理ToObject的_ObjAddRef和_ObjRelease的逻辑。Objective-C代码使用相同的逻辑调用retain和release。遗憾的是,导入包装类和上面讨论的接口表示的Objective-C对象没有ARC。在处理Objective-C对象时你必须在正确的时间点打电话给retain并释放你自己

弧和JAVA对象

从纸面上看,这是必须的,但就个人而言,我不相信它,例如,如果你在循环中这样做:

for i := 0 to 100000 do begin
  aJstring := StringToJstring('a text'); 
  aStr := JstringToString(aJstring);
end;
正常情况下,在正常情况下,它必须毫无问题地运行,但在delphi下,它将崩溃:(但无论如何,这里您没有.release,因此您没有选择权(除了将变量指定为nil)。但当您有选择时,我建议始终使用。disposeOF后跟nil
,您可能会赢得几天/几周/几个月的开发,摆脱一些讨厌的bug

注意:当我想要销毁一个对象时,我调用此函数:

{******************************}
Procedure ALFreeAndNil(var Obj);
var Temp: TObject;
begin
  Temp := TObject(Obj);
  if temp = nil then exit;
  TObject(Obj) := nil;

    {$IF defined(AUTOREFCOUNT)}
    if AtomicCmpExchange(temp.refcount{Target}, 0{NewValue}, 0{Compareand}) = 1 then begin // it's seam it's not an atomic operation (http://stackoverflow.com/questions/39987850/is-reading-writing-an-integer-4-bytes-atomic-on-ios-android-like-on-win32-win6)
      temp.Free;
      temp := nil;
    end
    else begin
      Temp.DisposeOf; // TComponent Free Notification mechanism notifies registered components that particular
                      // component instance is being freed. Notified components can handle that notification inside
                      // virtual Notification method and make sure that they clear all references they may hold on
                      // component being destroyed.
                      //
                      // Free Notification mechanism is being triggered in TComponent destructor and without DisposeOf
                      // and direct execution of destructor, two components could hold strong references to each
                      // other keeping themselves alive during whole application lifetime.
      {$IF defined(DEBUG)}          
        if (Temp.RefCount - 1) and (not $40000000{Temp.objDisposedFlag}) <> 0 then
          ALLog('ALFreeAndNil', Temp.ClassName + ' | Refcount is not null (' + Inttostr((Temp.RefCount - 1) and (not $40000000{Temp.objDisposedFlag})) + ')', TalLogType.warn);
      {$IFEND}
      temp := nil;
    end;
    {$ELSE}
    temp.Free;
    temp := nil;
    {$IFEND}

end; 
{***********************************}
程序ALFreeAndNil(var Obj);
var-Temp:TObject;
开始
温度:=TObject(Obj);
如果温度=零,则退出;
TObject(Obj):=零;
{$IF-defined(AUTOREFCOUNT)}
如果原子CMPExchange(温度参考计数