Lebensdauer des beibehaltenen Speichers in Swift-Schließungen

8

Im Vortrag von Advanced Swift von der WWDC 2014 gab der Sprecher dieses Beispiel eines Funktions-Memos mit Generics:

%Vor%

Ich habe Probleme, meinen Kopf um die Lebensdauer dieses memo var zu wickeln. Hat jeder Aufruf der Funktion fibonacci in memoized einen starken Verweis darauf? Und wenn ja, wie würden Sie diese Erinnerung freigeben, wenn Sie damit fertig sind?

    
Jamie Forrest 20.06.2014, 15:02
quelle

3 Antworten

12

In der Terminologie der C / Objective-C-Blöcke ist memo eine __block -Variable (in Swift müssen Sie __block nicht explizit schreiben, um Variablen als Referenz zu erfassen). Die Variable kann in einem Block (Closure) zugewiesen werden und alle Bereiche, die diese Variable sehen, sehen Änderungen von jeder anderen Variablen (sie teilen sich einen Verweis auf die Variable). Die Variable wird solange gültig sein, wie ein Block (closure), der sie benutzt (es gibt nur einen Block, der sie in diesem Fall benutzt) noch lebt. Nachdem der letzte Block, der ihn verwendet, freigegeben wird, verlässt die Variable den Gültigkeitsbereich. Wie das funktioniert, ist ein Implementierungsdetail.

Wenn diese Variable einen Objekt-Zeigertyp hätte, würde das Objekt, auf das gezeigt wird, von allen Blöcken beibehalten, die es erfassen. In diesem Fall lautet die Variable jedoch Dictionary , ein Strukturtyp, bei dem es sich um einen Werttyp handelt. Daher gibt es kein Speichermanagement, um das Sie sich kümmern müssen. Die Variable ist die Struktur und die Struktur lebt so lange wie die Variable. (Die Struktur selbst kann Speicher anderweitig zuweisen und sie in ihrem Destruktor freigeben, aber dies wird intern vollständig von der Struktur gehandhabt und die Außenseite sollte nicht wissen oder sich darum kümmern.)

Im Allgemeinen muss man sich keine Gedanken darüber machen, wie __block Variablen intern funktionieren. Aber im Grunde genommen ist die Variable in einer vereinfachten "Objekt" Art der Sache eingewickelt, wobei die tatsächliche "Variable" ein Feld dieses "Objekts" ist, welches durch Referenzzählen speichergeführt wird. Blöcke, die sie erfassen, enthalten "starke Referenzen" auf dieses Pseudoobjekt. Wenn ein Block auf dem Heap erstellt wird (technisch, wenn er aus Stackblöcken in den Heap kopiert wird), der diese Variable __block verwendet, erhöht er den Wert Referenzzahl; Wenn ein Block, der sie verwendet, freigegeben wird, verringert sich die Anzahl der Referenzen. Wenn die Referenzzählung auf 0 geht, wird dieses Pseudo- "Objekt" freigegeben, wobei zuerst der entsprechende Destruktor für seinen Variablentyp aufgerufen wird.

Um Ihre Frage zu beantworten, ist die "gespeicherte Fibonacci-Funktion" ein Block (Schließung). Und das ist es, was einen starken Bezug auf was auch immer die Variable memo enthält. "Anrufungen" haben keine starken oder schwachen Bezüge dazu; Wenn eine Funktion aufgerufen wird, verwendet sie den Verweis, den die Funktion selbst hat. Die Lebensdauer der Variable memo ist die Lebensdauer der "gespeicherten Fibonacci-Funktion" in diesem Fall, da sie die einzige Schließung ist, die diese Variable erfasst.

    
newacct 20.06.2014, 22:16
quelle
3

Jeder Aufruf von memoize() erstellt unabhängig von anderen Aufrufen seine eigene memo Variable. Es lebt so lange, wie die darauf bezogene Schließung lebt; Wenn die Schließung freigegeben wird, werden auch die von ihr erfassten Variablen (in diesem Fall memo ) freigegeben.

Man kann sich das so vorstellen, als würde man eine Struktur wie in diesem Pseudocode zurückgeben:

%Vor%     
hamstergene 20.06.2014 15:12
quelle
2

Der innere Block (Rückgabewert) behält das Memo bei, was bedeutet, dass das Memo so lange bestehen bleibt, wie das zurückgegebene blck beibehalten wird.

Bei jedem Aufruf der Memoize-Funktion wird eine neue Instanz von memo erstellt. Durch den Aufruf des zurückgegebenen Blocks werden keine neuen Memo-Instanzen erstellt.

Der Speicher wird freigegeben, wenn der zurückgegebene Block den Gültigkeitsbereich verlässt.

    
David Berry 20.06.2014 15:12
quelle

Tags und Links