簡體   English   中英

Windows版Firemonkey下的Delphi ARC

[英]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...finallyFree

另一方面,如果您編寫僅在ARC下必須運行的代碼,則可以安全地省略try...finallyFree

但是,在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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM