2010-02-06 6 views
9

eine aktuelle Frage Lese ich die Funktion identifiziertHolding auf den Kopf einer Sequenz

diskutiert auf den Kopf einer Sequenz
(def fib-seq 
    (lazy-cat [0 1] (map + (rest fib-seq) fib-seq))) 

als zu halten, aber es fiel mir ein, meine Antwort wieder zu lesen, die ich beschönigt hatte über die Details, als wären sie offensichtlich, also ging ich zurück um zu klären und kam zu kurz. Ich weiß, dass fib-seq eine Var ist, und solange es in der Nähe ist, wird es alle Elemente in der Sequenz enthalten, aber ich bin überhaupt nicht klar über die genaue Mechanik, wie genau die Sequenz festgehalten wird. Jede Klärung wäre erwünscht.

Antwort

11

Grundsätzlich gelten die normalen GC-Regeln ... Eine Sequenz ist nur ein Objekt und das Halten auf dem Kopf bedeutet das Halten einer Referenz auf dieses Objekt. Dies beinhaltet, so viel von der Sequenz zu behalten, wie bereits im Speicher realisiert wurde, weil Clojure-Sequenzen zwischengespeichert werden.

(Eine detailliertere Erläuterung folgt - das Fragment in bold für den Kern von ihm sehen ... ;-))

'A-Sequenz' in Clojure ein Objekt ist, das die iseq Schnittstelle implementiert. Dies stellt Methoden bereit, die das erste Element der Sequenz und den Rest der Sequenz extrahieren (ein anderes Objekt, das ISeq implementiert). Als ein wichtiges Detail achten diese nicht nur darauf, das korrekte Objekt (den ersten/Rest der Sequenz) zu berechnen und es an den Aufrufer zurückzugeben, sondern auch den berechneten Wert im Speicher zwischenzuspeichern, so dass nachfolgende Anforderungen schneller sind - und mehr Wichtig ist, dass alle Anfragen für dasselbe Element der Sequenz garantiert denselben Wert zurückgeben, auch wenn der ISeq auf einem veränderlichen Java-Objekt erzeugt wird, das sich irgendwann ändert. (Beachten Sie, dass dies für die unveränderliche Semantik von Clojure-Sequenzen absolut entscheidend ist.)

Ein Var hingegen ist ein Container, der grob gesagt einen "Zeiger" auf ein Java-Objekt darstellt. Wenn dies passiert, ein ISeq, dann solange der Var selbst ist kein Müll gesammelt (was es natürlich nie sein wird, wenn es eine Top-Level-Var in einem derzeit vorhandenen Namespace) oder Rebound, der ISeq selbst wird nicht Müll gesammelt werden, und insbesondere der Speicher, den es für das Zwischenspeichern ersten/Rest der Sequenz verwendet, wird nicht freigegeben.

Wie für die anderen Elemente der Sequenz: der 'Rest' der ISeq an den Var gebunden ist ein ISeq selbst. Außerdem wird es vom ersten ISeq zwischengespeichert. Daher wird das erste Element des 'Rest' ISeq eines ISeq, das an Var gebunden ist, nie Müll sein, da ein Verweis darauf durch den 'Rest' ISeq des ISeq, der an Var gebunden ist, gehalten wird und dieses ISeq nicht Sei GC'd, weil es als die 'Rest'-Komponente durch den ISeq, der an den Var gebunden ist, zwischengespeichert wird, was wiederum nicht GC'd ist, solange es an den Var gebunden ist, was wiederum normalerweise nicht der Fall ist GC'd, weil es ein Top-Level-Var in einem Namespace ist.

Klar, dass die Var wird GC'd werden, wenn er von seinem Namensraum (ns-unmap) oder dem Namensraum selbst geworfen wird (remove-ns) auf gehalten hört auf werden. Wenn es zufällig einen ISeq gegeben hat, wird dieser ISeq genau dann gecodiert, wenn er nicht von irgendeinem anderen Code gehalten wird - natürlich gelten die üblichen GC-Regeln. Für Bindungen, die mit binding und lokalen Bindungen eingeführt wurden, die mit let eingeführt wurden, gelten alle oben genannten Modulo-Lebensdauerprobleme der Bindungen. (Welche sind kein Thema dieser Q.)

+0

Was ist die Var, die auf der Sequenz hält? Erzeugt die Definition der Funktion fib-seq eine var, die auf die Funktion verweist, und wenn diese Funktion eine Sequenz zurückgibt, behält die Funktion einen Verweis auf diese Sequenz bei? Wird irgendeine Funktion, die eine Sequenz zurückgibt, daran festhalten? –

+0

Das Beispiel in Ihrer Frage definiert überhaupt keine Funktion!Beachten Sie, dass Sie 'def' und nicht' defn' verwenden, und das, worauf Sie 'fib-seq' beziehen, ist eine Sequenz, keine Funktion. In diesem speziellen Fall ist das Var, nach dem das Symbol 'fib-seq' im aktuellen Namensraum aufgelöst wird, nachdem Ihr Beispiel' def'-Formular ausgewertet wurde, das, was die Folge von Fibonacci-Zahlen enthält, die von der 'Lazy-cat'-Form erzeugt wird . Die Tatsache, dass dies nicht in eine Endlosschleife geht, ist darauf zurückzuführen, dass "Lazy-Cat" eine * Lazy * -Sequenz erzeugt, die realisiert werden muss, wenn Sie Elemente davon anfordern. –

+2

Ihre Antwort von dieser anderen Frage, zu der Sie in diesem Q verlinken, enthält die Funktion von Christophe Grand, die die Reihenfolge aller Fibonacci-Zahlen auf faule Weise erzeugt und ohne den Kopf festzuhalten - beachten Sie, dass in dieser Funktion * kein Name vergeben wird Gesamtheit der Sequenz *. Wenn Sie etwas wie '(def fib-seq (fibo))' gemacht haben, dann würden Sie sicher so viel von der Sequenz behalten, wie Sie es für möglich gehalten hätten, solange diese Bindung nicht durch eine andere geändert wurde. def fib-seq ...) 'expression oder' alter-var-root'. Siehe auch http://clojure.org/special_forms für Informationen zu 'def' /' defn'. –

Verwandte Themen