2016-05-21 43 views
5

我正在從頭開始編寫一個簡單的lisp解釋器。我有一個全局環境,在評估文件中的所有表單時,頂級變量都會被綁定。當文件中的所有表單都被評估過時,頂層env和其中的所有鍵值數據結構都被釋放。何時在lisp解釋器中釋放閉包的內存

當評估者遇到lambda表單時,它會創建一個包含3件東西的PROC對象:應用過程時要在本地框架中綁定的參數列表,該函數的主體以及指向環境它是在創建,例如:

​​3210

將產生什麼樣的內部:

PROC- args: x, 
     body: x, 
     env: pointer to top level env 

當施加PROC中,爲幀和第創建了一個新的環境本地綁定將在那裏進行,以允許使用適當的綁定來評估身體。這個框架環境包含一個指向它的閉包的指針,以允許在THAT中進行變量查找。在這種情況下,這將是全球環境。在對PROC正文進行評估後,我可以釋放與其關聯的所有單元格,包括其框架環境,並退出時不會發生內存泄漏。

我的問題是高階函數。試想一下:

(define conser 
    (lambda (x) 
     (lambda (y) (cons x y)))) 

它有一個參數,併產生另一個函數的函數,將利弊這樣的說法你進入它的東西。所以,

(define aconser (conser '(1))) 

將產生該cons'es '(1)到任何被傳遞到它的功能。例如:

(aconser '(2)) ; ((1) 2) 

我在這裏的問題是,aconser必須保留一個指向其創建的環境中,即中conser時通過調用(conser '(1))製作。當aconser應用PROC時,其幀必須指向定義爲aconser時存在的conser的幀,因此在應用它之後我不能釋放conser的幀。我不知道在應用時如何釋放與lambda框架相關聯的內存,並且還支持這種持久高階函數。

我能想到的一些解決方案的:

  • 某種類型的ARC

  • 的複製封閉環境到評價PROC的幀時,它產生

這似乎暗示here。因此,我不會將一個指針保存在PROC對象中,而是將它關閉,我會......複製閉包環境,並將指針直接存儲在單元格中的?這不僅僅是踢一個更深的水平,導致同樣的問題?

  • 遞歸代高階函數體內部在讀取時間標籤

我擔心我可能失去了一些東西很簡單,我也很好奇,怎麼這個程序在其他lisp語言和其他通常使用閉包的語言中得到支持。我沒有太多的運氣來尋找答案,因爲問題是非常具體的,甚至可能是這個實現(我承認我只是作爲一個學習項目脫離了我的帽子),而我能找到的大部分內容只是解釋了具體情況從語言實施的角度來看,而不是語言正在實施的語言。

Here is a link到我的來源的相關行,如果它是有用的,我很高興闡述,如果這個問題不夠詳細,足以描述問題徹底。謝謝!

+1

我可能會遺漏一些東西,但是你說:「在評估PROC體之後,我可以釋放與它相關的所有單元格,包括它的框架環境,並退出時沒有內存泄漏。」。你不能多次重複使用閉包嗎?在這種情況下,您將過早釋放環境。 – coredump

+0

這正是問題所在。我在這裏區分了閉包(無論env是一個lambda是否已經被eval了,導致一個proc)和框架,這是一個proc內部變量在應用時的本地綁定。我可能會誤解這些術語,雖然... – jfo

+0

因此,如果我有一個只有單層深度的lambda表達式,每次應用它時都會重新創建它的框架,並使用傳遞給它的任何參數。 – jfo

回答

1

這種處理方式通常在天真的口譯員中是使用垃圾收集器(GC)並在GC堆中分配激活幀。所以你從不明確地釋放這些幀,你可以讓GC在適用的時候釋放它們。

在更復雜的實現,你可以用一個稍微不同的方法:

  • 時創建一個封閉,不存儲指向當前的環境。相反,複製閉包使用的那些變量的值(它被稱爲lambda的自由變量)。 並將封閉體更改爲使用這些副本,而不是在環境中查找這些變量。它被稱爲關閉轉換
  • 現在您可以將您的環境視爲普通堆棧,並在您退出示波器後立即釋放激活幀。
  • 你仍然需要一個GC來決定什麼時候關閉關閉可以被釋放。
  • 這反過來需要一個「賦值轉換」:複製變量的值意味着如果這些變量被修改,語義的變化。因此,要恢復原始語義,您需要查找那些「複製到閉包」以及「修改」的變量,並將它們變爲「參考單元」(例如缺陷單元格,您可以在其中保留值car),以便副本不會複製該值,而只是將引用複製到保存值的實際位置。 [注意:這樣的實現顯然意味着避免使用setq並使用更實用的風格可能會更有效率。 ]

更爲複雜的實現也具有優勢,它可以爲空間語義提供了一種安全:封閉只會留住數據,它實際上是指,違背了幼稚的方法,即關閉結束指的是整個周圍的環境,因此可以阻止GC收集實際未被引用的數據,但恰好在封閉捕獲時發生在環境中。

+0

ty,這是一個徹底的答案,基本上反映了我的問題後研究顯示了我。對於我的玩具lisp,我決定GC不在我原來的項目範圍內,所以我沒有實現它,但我計劃在我的下一次嘗試:) – jfo

+0

你可以閱讀關於我在[這裏]結束了什麼( http://blog.jfo.click/sild-is-a-lisp-dialect/)。 – jfo