Firemonkey for Windows下的Delphi ARC
我正在看Marco谈论自动参考计数的视频。我已经知道在Android和iOS(Firemonkey)下,我的对象是ref计数的,所以我不需要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下运行
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(温度参考计数