第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號(hào)安全,請(qǐng)及時(shí)綁定郵箱和手機(jī)立即綁定
已解決430363個(gè)問(wèn)題,去搜搜看,總會(huì)有你想問(wèn)的

如何在Android / iOS中釋放組件

如何在Android / iOS中釋放組件

函數(shù)式編程 2019-12-02 13:57:22
我TEdit在Android中的表單上動(dòng)態(tài)創(chuàng)建一個(gè):edit := TEdit.Create(Self);我想使用釋放它edit.Free,但它仍在表單中。該代碼在win32上可以正常工作,但在Android上失敗。不僅對(duì)于TEdit,而且對(duì)于使用Android或iOS的任何組件,似乎都發(fā)生了同樣的情況。
查看完整描述

3 回答

?
慕后森

TA貢獻(xiàn)1802條經(jīng)驗(yàn) 獲得超5個(gè)贊

簡(jiǎn)短答案

TComponent在Delphi ARC編譯器(當(dāng)前為Android和iOS)下釋放任何后代對(duì)象時(shí),應(yīng)遵循兩個(gè)規(guī)則:


DisposeOf無(wú)論對(duì)象是否擁有所有者,都必須使用

在析構(gòu)函數(shù)中或在DisposeOf調(diào)用后不久引用未超出范圍的情況下,也應(yīng)將對(duì)象引用設(shè)置為nil(陷阱詳細(xì)說(shuō)明)

擁有DisposeOfAndNil方法可能會(huì)很有吸引力,但是ARC使它比舊FreeAndNil方法復(fù)雜得多,我建議使用簡(jiǎn)單DisposeOf - nil序列來(lái)避免其他問(wèn)題:


Component.DisposeOf;

Component := nil;

盡管在許多情況下,即使不遵守上述規(guī)則,代碼也可以正常運(yùn)行,但此類代碼相當(dāng)脆弱,很容易被看似無(wú)關(guān)的地方引入的其他代碼破壞。


ARC內(nèi)存管理中的DisposeOf

DisposeOf打破ARC。它違反了ARC的黃金法則。任何對(duì)象引用都可以是有效的對(duì)象引用,也可以是nil,并且引入了第三種狀態(tài)- 放置了“僵尸”對(duì)象引用。


任何試圖了解ARC內(nèi)存管理的人都應(yīng)該看一下DisposeOf只是解決了Delphi特定框架問(wèn)題的附件,而不是真正屬于ARC本身的概念。


為什么DisposeOf在Delphi ARC編譯器中存在?

TComponent類(及其所有后代)在設(shè)計(jì)時(shí)考慮了手動(dòng)內(nèi)存管理。它使用與ARC內(nèi)存管理不兼容的通知機(jī)制,因?yàn)樗蕾囉谄茐奈鰳?gòu)函數(shù)中的強(qiáng)引用周期。由于它TComponent是Delphi框架所依賴的基本類之一,因此它必須能夠在ARC內(nèi)存管理下正常運(yùn)行。


除了Free Notification機(jī)制之外,Delphi框架中還有其他類似的設(shè)計(jì)適用于手動(dòng)內(nèi)存管理,因?yàn)樗鼈円蕾囉谄茐奈鰳?gòu)函數(shù)中的強(qiáng)引用周期,但是這些設(shè)計(jì)不適合ARC。


DisposeOf方法可以直接調(diào)用對(duì)象析構(gòu)函數(shù),并使這些舊代碼可以與ARC一起播放。


這里必須注意一件事。即使在今天編寫(xiě)了代碼,使用或繼承的任何代碼也將在適當(dāng)?shù)腁RC管理的情況下TComponent自動(dòng)成為舊代碼。


從艾倫·鮑爾(Allen Bauer)的博客引用進(jìn)入ARC方面


那么DisoseOf還可以解決什么呢?在各種Delphi框架(包括VCL和FireMonkey)中,將活動(dòng)的通知或列表管理代碼放在類的構(gòu)造函數(shù)和析構(gòu)函數(shù)中非常普遍。TComponent的所有者/擁有模型是這種設(shè)計(jì)的關(guān)鍵示例。在這種情況下,現(xiàn)有的組件框架設(shè)計(jì)依賴于許多活動(dòng),而不是在析構(gòu)函數(shù)中進(jìn)行簡(jiǎn)單的“資源管理”。


TComponent.Notification()是此類事情的一個(gè)關(guān)鍵示例。在這種情況下,“處置”組件的正確方法是使用DisposeOf。TComponent派生通常不是瞬態(tài)實(shí)例,而是一個(gè)壽命更長(zhǎng)的對(duì)象,它也由組成表單,框架和數(shù)據(jù)模塊之類的其他組件實(shí)例的整個(gè)系統(tǒng)包圍。在這種情況下,使用DisposeOf是合適的。


DisposeOf如何工作

為了更好地了解DisposeOf調(diào)用時(shí)將發(fā)生的情況,有必要了解Delphi對(duì)象銷毀過(guò)程的工作方式。


在ARC和非ARC Delphi編譯器中釋放對(duì)象涉及三個(gè)不同的階段


調(diào)用destructor Destroy方法鏈

清理對(duì)象管理的字段-字符串,接口,動(dòng)態(tài)數(shù)組(也在包含普通對(duì)象引用的ARC編譯器下)

從堆釋放對(duì)象內(nèi)存

使用非ARC編譯器發(fā)布對(duì)象


Component.Free ->立即執(zhí)行階段 1 -> 2 -> 3


使用ARC編譯器發(fā)布對(duì)象


Component.Free或Component := nil->減少對(duì)象引用計(jì)數(shù),后跟a)或b)


a)如果對(duì)象引用計(jì)數(shù)為0->立即執(zhí)行階段1 -> 2 -> 3

b)如果對(duì)象引用計(jì)數(shù)大于0,則什么也沒(méi)有發(fā)生

Component.DisposeOf->立即執(zhí)行stage 1,stages,2并且3將在對(duì)象引用計(jì)數(shù)達(dá)到0時(shí)稍后執(zhí)行。DisposeOf不會(huì)減少調(diào)用引用的引用計(jì)數(shù)。


TComponent通知系統(tǒng)


TComponent Free Notification機(jī)制通知注冊(cè)的組件特定的組件實(shí)例正在釋放。被通知的組件可以在虛擬Notification方法中處理該通知,并確保它們清除了對(duì)銷毀的組件可能持有的所有引用。


在非ARC編譯器下,該機(jī)制可確保您不會(huì)導(dǎo)致指向無(wú)效對(duì)象(已釋放對(duì)象)的懸空指針結(jié)束;在ARC編譯器下,清除對(duì)銷毀組件的引用將減少其引用計(jì)數(shù)并破壞強(qiáng)引用周期。


Free Notification在TComponent析構(gòu)函數(shù)中觸發(fā)了機(jī)制,并且在沒(méi)有DisposeOf直接執(zhí)行析構(gòu)函數(shù)的情況下,兩個(gè)組件可以相互保持強(qiáng)引用,從而在整個(gè)應(yīng)用程序生存期內(nèi)保持自身的生命。


FFreeNotifies包含對(duì)通知感興趣的組件列表的list聲明為FFreeNotifies: TList<TComponent>,它將存儲(chǔ)對(duì)任何已注冊(cè)組件的強(qiáng)引用。


因此,例如,如果您在表單上有TEdit和TPopupMenu并將該彈出菜單分配給edit的PopupMenu屬性,則edit將在其FEditPopupMenu字段中保留對(duì)彈出菜單的強(qiáng)引用,而彈出菜單將在其FFreeNotifies列表中保留對(duì)其進(jìn)行編輯的強(qiáng)引用。如果要釋放這兩個(gè)組件中的任何一個(gè),則必須調(diào)用DisposeOf它們,否則它們將繼續(xù)存在。


盡管您可以嘗試手動(dòng)跟蹤那些連接并打破強(qiáng)大的參考周期,然后再釋放在實(shí)踐中可能不那么容易的那些對(duì)象。


后面的代碼基本上會(huì)泄漏ARC下的兩個(gè)組件,因?yàn)樗鼈儗⑾嗷ケ3謴?qiáng)引用,并且在過(guò)程完成之后,您將不再具有指向這些組件中任何一個(gè)的外部引用。但是,如果替換Menu.Free為Menu.DisposeOf,則會(huì)觸發(fā)Free Notification機(jī)制并破壞強(qiáng)參考周期。


procedure ComponentLeak;

var

  Edit: TEdit;

  Menu: TPopupMenu; 

begin

  Edit := TEdit.Create(nil);

  Menu := TPopupMenu.Create(nil);


  Edit.PopupMenu := Menu; // creating strong reference cycle


  Menu.Free; //  Menu will not be released because Edit holds strong reference to it

  Edit.Free; // Edit will not be released because Menu holds strong reference to it

end;

DisposeOf的陷阱

除了破壞ARC之外,它本身也是不好的,因?yàn)楫?dāng)您破壞ARC時(shí),它并沒(méi)有太多使用DisposeOf,開(kāi)發(fā)人員還應(yīng)注意實(shí)現(xiàn)的兩個(gè)主要問(wèn)題。


1. DisposeOf不減少調(diào)用參考 QP報(bào)告RSP-14681 上的參考計(jì)數(shù)


type

  TFoo = class(TObject)

  public

    a: TObject;

  end;


var

  foo: TFoo; 

  b: TObject;


procedure DoDispose;

var

  n: integer;

begin

  b := TObject.Create;

  foo := TFoo.Create;

  foo.a := b;

  foo.DisposeOf;

  n := b.RefCount; // foo is still alive at this point, also keeping b.RefCount at 2 instead of 1

end;


procedure DoFree;

var

  n: integer;

begin

  b := TObject.Create;

  foo := TFoo.Create;

  foo.a := b;

  foo.Free;

  n := b.RefCount; // b.RefCount is 1 here, as expected 

end;

2. DisposeOf不清理實(shí)例內(nèi)部托管類型參考 QP報(bào)告RSP-14682


type

  TFoo = class(TObject)

  public

    s: string;

    d: array of byte;

    o: TObject;

  end;


var

  foo1, foo2: TFoo;


procedure DoSomething;

var

  s: string;

begin

  foo1 := TFoo.Create;

  foo1.s := 'test';

  SetLength(foo1.d, 1);

  foo1.d[0] := 100;

  foo1.o := TObject.Create;

  foo2 := foo1;

  foo1.DisposeOf;

  foo1 := nil;

  s := IntToStr(foo2.o.RefCount) + ' ' + foo2.s + ' ' + IntToStr(foo2.d[0]); 

  // output: 1 test 100 - all inner managed references are still alive here, 

  // and will live until foo2 goes out of scope

end;

解決方法


destructor TFoo.Destroy;

begin

  s := '';

  d := nil;

  o := nil;

  inherited;

end;

上述問(wèn)題的綜合影響可以以不同的方式體現(xiàn)出來(lái)。從保留超出必要的分配內(nèi)存到難以捕獲由所包含的非擁有對(duì)象和接口引用的錯(cuò)誤,意外引用計(jì)數(shù)引起的錯(cuò)誤。


由于DisposeOf不會(huì)減少調(diào)用引用的引用計(jì)數(shù),因此nil在析構(gòu)函數(shù)中進(jìn)行此類引用很重要,否則整個(gè)對(duì)象層次結(jié)構(gòu)的存活時(shí)間可能會(huì)比所需時(shí)間長(zhǎng)得多,有時(shí)甚至在整個(gè)應(yīng)用程序生命周期中也是如此。


3. DisposeOf不能用于解析所有循環(huán)引用


最后但并非最不重要的問(wèn)題DisposeOf是,只有在析構(gòu)函數(shù)中有代碼可以解析循環(huán)引用時(shí),它才會(huì)中斷循環(huán)引用,就像TComponent通知系統(tǒng)一樣。


此類未由析構(gòu)函數(shù)處理的循環(huán)應(yīng)使用[weak]和/或[unsafe]引用之一上的屬性來(lái)中斷。這也是ARC的首選做法。


DisposeOf不應(yīng)將其用作打破所有參考周期(從未設(shè)計(jì)過(guò)的參考周期)的快速解決方案,因?yàn)樗鼘o(wú)法正常工作,并且濫用它可能導(dǎo)致難以跟蹤的內(nèi)存泄漏。


不會(huì)被破壞的循環(huán)的簡(jiǎn)單示例DisposeOf是:


type

  TChild = class;


  TParent = class(TObject)

  public

    var Child: TChild;

  end;


  TChild = class(TObject)

  public

    var Parent: TParent;

    constructor Create(AParent: TParent);

  end;


constructor TChild.Create(AParent: TParent);

begin

  inherited Create;

  Parent := AParent;

end;


var

  p: TParent;

begin

  p := TParent.Create;

  p.Child := TChild.Create(p);

  p.DisposeOf;

  p := nil;

end;

上面的代碼將泄漏子對(duì)象實(shí)例和父對(duì)象實(shí)例。結(jié)合DisposeOf無(wú)法清除內(nèi)部托管類型(包括字符串)的事實(shí),這些泄漏可能會(huì)非常龐大,具體取決于您存儲(chǔ)在內(nèi)部的數(shù)據(jù)類型。打破這種循環(huán)的唯一(正確)方法是更改TChild類聲明:


  TChild = class(TObject)

  public

    [weak] var Parent: TParent;

    constructor Create(AParent: TParent);

  end;


查看完整回答
反對(duì) 回復(fù) 2019-12-02
  • 3 回答
  • 0 關(guān)注
  • 877 瀏覽

添加回答

舉報(bào)

0/150
提交
取消
微信客服

購(gòu)課補(bǔ)貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動(dòng)學(xué)習(xí)伙伴

公眾號(hào)

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號(hào)