私のクラスプロジェクトでは、(シンプルな)Schemeコンパイラを実装する必要があります。Scheme/Lisp実装でガベージコレクタを使用していません
この時点で、私はさまざまな機能を実装する方法をブレーンストーミングしています。
典型的なSchemeの実装が複雑なGCを悩ますのはなぜですか?コードが本当に機能している場合(副作用なし)、現在実行されていない関数は割り当てられたメモリを保持できません。今まで! (漏れがなければ!)
したがって、ほとんどの命令型言語の後に続くC
のような戦略、つまりスタック割り当てを使用しないでください。新しい語彙コンテキスト(すなわち、(define (foo ..)
または(letrec ...
)が入力されるたびに、変数記憶域をスタックに割り当てて、コンテキストが終了したら単純にスタックポインタを調整します。
スキームにはmalloc()
があり、事前定義された型だけの割り当てが許可されているため、単純な実装ではプールまたはゾーンのアロケータを使用できるため、「スタック」は決してフラグメント化しません。
私はクロージャを実装する必要はありませんが、バインディングされた値を別のスタックにコピーすることで、クロージャの状態を排他的に追跡するために使用することもできます。
思考?
しかし、コードは本当に機能的ではないので、 'set!'、 'set-car!'や 'set-cdr!'のような状態を変更する操作は、標準Schemeの実装の一部です。あなたの(シンプルな)Schemeコンパイラがこれらの操作を許さず、クロージャを実装する必要がないなら、より簡単なGC戦略が可能かもしれません。 –
単純な例を考えてみましょう:関数はリストを返します。関数は、元のリストのすべての2番目の要素からなる新しいリストを作成します。あなたの地域分析は、どのように元のリスト要素のどの部分が第2の機能の終了時にもはや必要ではないと推定するでしょうか?最も基本的なラムダ計算でさえも領域を推論する方法はまったくありません。 –
Schemeコンパイラは、Schemeランタイムのガベージコレクタを実装するという問題からはるかに離れています。最初に「シンプルな」コンパイラに注目してください。 – GoZoner