[英]Delphi ARC under Firemonkey for Windows
我正在觀看這段視頻,其中Marco在談論自動引用計數。 我已經知道在Android和iOS(Firemonkey)下我的對象被引用計數,因此我不需要try finally
塊。
參考計數實現是否與平台(VLC或FMX)或操作系統一起工作?
我的意思是:
var a: TObject;
begin
a := TObject.Create;
a.use1;
a.use2;
end;
如果Firemonkey在Android / iOS / Mac上運行,則對Firemonkey很有好處,我沒有內存泄漏。 但是,如果我在Windows(並且使用過Firemonkey)下運行此程序,由於沒有引用計數,我是否還會發生內存泄漏?
無論如何,從視頻中我了解到,即使在ARC的情況下, try finally
調用Free
try finally
不錯的用法,但這毫無用處。
ARC是按OS平台而不是GUI框架實現的。
Android,iOS和Linux編譯器對對象使用ARC內存管理。 Windows和OSX編譯器使用經典的手動內存管理,其中僅在接口引用而不是對象上支持ARC。
VCL是僅Windows的框架,僅在經典編譯器下運行。
另一方面,FMX作為跨平台框架,根據運行的OS平台使用不同的內存管理系統。
try...finally Free
在ARC編譯器上, try...finally Free
塊確實是沒用的(在與Free
方法結合使用的安全保護對象的上下文中)。 但是,如果編寫必須在兩個內存管理系統下都可以使用的跨平台代碼,則必須使用try...finally
和Free
。
另一方面,如果您編寫僅在ARC下必須運行的代碼,則可以安全地省略try...finally
和Free
。
但是,在ARC上,您可能需要使用Free
(在ARC編譯器上,它轉換為nil
分配),或者如果需要在某個點釋放對象,則直接將nil
分配給對象/接口引用,然后再將其引用超出范圍。
還有就是上面的規則一個重要的例外- TComponent
的后代(包括Firemonkey GUI組件和控件),其中try...finally Free
塊不得不被替換try...finally DisposeOf
如果要創建和釋放在那些代碼實例。
您可以在如何在Android / iOS中釋放組件中閱讀更多內容
這里要注意的重要事項: DisposeOf
具有非常特定的用途,它不是打破參考周期並在ARC下釋放對象的通用解決方案。 在任何地方盲目使用它可能會導致內存泄漏。 可以在上面的“問題/ 陷阱”的“陷阱”中找到更詳細的答案。
引用計數ARC在delphi下非常令人困惑,它使開發變得更加困難,因為它的設計不正確(在delphi下)。
首先,它是在RTL中構建的,它與String具有的功能非常相似。 它適用於平板電腦(firemonkey)和OS(僅適用於android / ios / unix)。 因此,如果您要構建同時針對窗口的多平台代碼(最有可能,至少是為了調試代碼) ,則無論如何都需要保持try ... finally .. end; (是的,我說你,非常糟糕的設計)。 因此,不用.free可以省去您的示例,除非您想在移動設備上進行調試(而且每次編譯需要3分鍾,祝您好運,這簡直是不可能的)
注意 :為了使您的代碼盡可能地兼容,一個好的規則是用.disposeOF替換所有.free,然后用nil替換,因為在移動設備下,free是一個無操作操作,並且您的對象不會被破壞,並且可以在非常意外的時間被銷毀(或者在最壞的情況下根本不會被銷毀,如果使用例如TTask,這很常見)。 這些情況並不罕見,特別是如果您經常使用在后台捕獲中為您的對象創建的匿名過程(對過程的引用)。
始終牢記,循環引用很容易滿足且很難檢測
。
在您還必須知道(您沒有問,但是我要擴展一點答案)之后,它們就是delphi Tobject,java對象,IOS目標C對象和Interface。 每個人都有自己的規則並使每個人困惑,最后沒有人真正知道它是如何工作的(是ARC糟糕的設計的一部分也是它給人帶來的困惑),即使emb開發人員在他們的delphi源代碼中也會犯錯,尋找舉例說明這個問題: delphi + ios:使用objective-c對象發布/保留和引用計數,這很瑣碎,但是沒有任何答案
ARC和Objective-C包裝的對象
Delphi NextGen編譯器為所有Delphi對象實現自動引用計數(ARC)。 編譯器將為您管理TObject的__ObjAddRef和__ObjRelease的邏輯。 Objective-C代碼使用相同的邏輯來調用保留和釋放。 不幸的是,由導入包裝類和上面討論的接口表示的Objective-C對象沒有ARC。 處理Objective-C對象時,您必須在正確的位置調用保留並釋放自己。
ARC和JAVA對象
在紙上,它必須有效,但是個人而言,我不信任它,例如,如果您循環執行:
for i := 0 to 100000 do begin
aJstring := StringToJstring('a text');
aStr := JstringToString(aJstring);
end;
通常,它在正常情況下必須正常運行,但是在delphi下,它會崩潰:(但是無論如何這里您都沒有.release,所以您沒有選擇的余地(將變量賦給nil除外)。但是當您有一個選擇,這就是為什么我建議始終使用.disposeOF后跟nil的原因 ,您可能會贏得幾天/幾周/一個月的開發,避免了一些討厭的錯誤。
注意:我要銷毀對象時調用此函數:
{******************************}
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后refcount不為0,則它會在日志中生成警告(在調試下),您可以進行調查
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.