2012-03-27 14 views
12

私はForthを学んでいて、誰かがメモリ管理の一般的な仕組みを理解できるように助けてくれるのか不思議でした。現時点では、私はCのスタック(つまり、ヒープのパラダイム)の経験があるだけです。Forthでのメモリ管理

私が理解するところでは、辞書またはヒープに割り当てることができます。辞書はCのスタックのように高速化/優先化されていますか?しかし、Cとは異なり、スコープや自動スタックの再利用はないので、もしグローバルデータ構造のためのディクショナリを使っているのであれば、私は思っています。

ヒープが行く限り、それはCにかなり似ていますか?ヒープ管理は標準(ANS)のコンセプトですか、それとも実装定義ですか?

答えて

13

これは辞書でも、ヒープでもありません。ヒープに相当するのは辞書です。しかし、ヒープよりもスタックのように機能するという厳しい制限のために、新しい単語が辞書の末尾に追加されます(割り当てはALLOTで割り振り、FORGETまたはFREEで解放します)。すべて新しい単語POPs))。

実装はメモリレイアウトを制御し、従来のヒープ(またはガベージコレクション)を実装できます。例はA FORTH implementation of the Heap Data Structure for Memory Mangement(1984)です。別の実装形態は、Dynamic Memory Heaps for Quartus Forth(2000)です。

多くは、実装に依存します。例えば、メモリレイアウトは、2つのブロックバッファ(位置はBLOCKTIB)、テキスト入力バッファとその値と低レベル/プリミティブ関数、最下位部分、中間の辞書)、戻りスタックとパラメータスタックは、先頭にとなります。

ディクショナリの上にある最初の使用可能なバイトのアドレスは、HEREによって返されます(ディクショナリの展開に応じて変更されます)。

一時的にデータを保存するために、辞書の上にスクラッチパッド領域(PADから返されるアドレス)もあります。スクラッチパッド領域は空きメモリと見なすことができます。

操作の優先モードは、ローカル変数またはヒープの代わりにできるだけスタックを使用することです。

p。 「FORTHの記憶、辞書、語彙」の章の286(Forthの特定の版、MMSFORTHについて)Forth:テキストと参照。 Mahlon G. KellyおよびNicholas Spies。 ISBN 0-13-326349-5/0-13-326331-2(pbk。)。 Prentice-Hallによる1986年。

2

一部のForth実装では、リターンスタックフレームのローカル変数とメモリブロックの割り当てがサポートされています。たとえば、SP-Forth

lib/ext/locals.f 
lib/ext/uppercase.f 

100 CONSTANT /buf 

: test (c-addr u --) { \ len [ /buf 1 CHARS + ] buf } 
    buf SWAP /buf UMIN DUP TO len CMOVE 
    buf len UPPERCASE 
    0 buf len + C! \ just for illustration 
    buf len TYPE 
; 

S" abc" test \ --> "ABC" 
3

Peter Mortensenは非常にうまくレイアウトしました。私は、Cプログラマを助けるかもしれないいくつかのノートを追加します。

スタックは、Cという用語に「auto」変数と最もよく似ており、一般にローカル変数と呼ばれるものです。スタックの値にはいくつかの名前を付けることができますが、ほとんどのプログラマは値を命名する必要がないようにコードを記述しようとします。

辞書は、Cプログラミングの観点から、「静的データ」として最もよく見ることができます。ディクショナリ内のアドレス範囲を予約できますが、通常は割り当て後にサイズを変更しない静的なデータ構造およびプールを作成するためにALLOTおよび関連ワードを使用します。リアルタイムで拡大できるリンクされたリストを実装したい場合は、必要なリンクセルのための十分なスペースを確保し、描画できるセルの空きリストを維持するための単語を書いてください。この種のものは自然に実装されています。独自のものを書くことは、ポインタ管理スキルを磨く良い方法です。

ヒープ割り当ては、現代の多くのForthで利用でき、標準では、Cでmalloc()、free()、realloc()のように動作するALLOCATE、FREEおよびRESIZEワードを定義しています。ヒープであり、一般的には、スタックを解放する前に間違ってポインタを失うことがないように、スタック内の変数やその他の永久的な構造体にアドレスを格納することをお勧めします。補足として、これらのワード(ファイルのI/Oワードと一緒に)は、エラーが発生した場合にはゼロでないステータスをスタック上に返します。この規則は、例外処理メカニズムとうまくフィットし、あなたのようなコードを記述することができます:

variable PTR 
1024 allocate throw PTR ! 
\ do some stuff with PTR 
PTR @ free throw 
0 PTR ! 

またはフリー/割り当てのより複雑な場合は、やや人工例えば:

\ A simple 2-cell linked list implementation using allocate and free 
: >link (a -- a) ; 
: >data (a -- a) cell + ; 
: newcons (a -- a) \ make a cons cell that links to the input 
    2 cells allocate throw tuck >link ! ; 
: linkcons (a -- a) \ make a cons cell that gets linked by the input 
    0 newcons dup rot >link ! ; 
: makelist (n -- a) \ returns the head of a list of the numbers from 0..n 
    0 newcons dup >r 
    over 0 ?do 
    i over >data ! linkcons (a -- a) 
    loop >data ! r> ; 
: walklist (a --) 
    begin dup >data ? >link @   dup 0= until drop ; 
: freelist (a --) 
    begin dup >link @ swap free throw dup 0= until drop ; 
: unittest 10 makelist dup walklist freelist ; 
+0

これは少し遅れているかもしれません。リンクの目的を説明してもらえますか? –

+0

Sorry - > linkは、ポインターから "コンスセル"(LISPの用語を借用)のアクセッサで、 "次の"ポインタのアドレスになります。この実装では、「次へ」ポインタがコンスセルに格納されている最初のものであるため、NO-OPとして実装されています。 –

9

基本的な質問をします新しいForthユーザーが必要とする方法で答えられていないので、私はそれを実行します。

Forthのメモリは非常にターゲットに依存する可能性があるので、コードとデータが一緒に楽しく暮らせるフラットなメモリ空間であるという単純なモデルに限定して説明します。 (セグメンテーションされたメモリモデル、またはデータ用のコードおよびRAM用のFLASHメモリまたは他のより複雑なモデル)

辞書は通常、メモリの一番下から始まり、Forthシステムによって上向きに割り当てられます。単純なシステムの2つのスタックは、高メモリに存在し、通常は2つのCPUレジスタを指します。 (非常にシステムに依存)

最も基本的なレベルでは、メモリは単に辞書ポインタ変数の値を変更することによって割り当てられます。 (時々DPと呼ばれる)

プログラマーは、通常、この変数に直接アクセスするのではなく、いくつかの上位ワードを使用して制御します。

前述のように、 'HERE'は、辞書空間で次に使用可能なアドレスを返します。言及されていなかったことは、ここでは変数DPの値を取得することによって定義されたことでした。フォースで(システム依存、ここではなく説明のために有用)

は 'HERE' のようになります。

:HERE( - ADDR)DP @;

これだけです。

いくつかのメモリを割り当てるには、ここで上に移動する必要があります。これは「ALLOT」という単語で行います。

'ALLOT'のForth定義は、単にパラメータスタックから数値を取り出し、それをDPの値に加算します。だからそれ以上のものではない:

:ALLOT(n - )DP +! ; \ '+!内容変数にnを加えます。

私たちが作成した内容が 'ALLOTED'メモリ内に安全に保存されるように、新しい定義を作成するときにALLOTがFORTHシステムによって使用されます。

すぐには分かりませんが、ALLOTは負の数を取ることができるので、辞書のポインタを上下に動かすことができます。だから、あなたには、いくつかのメモリを割り当てると、このようにそれを返すことができます:それはアップし、このような

HEX 100充てる

とフリー:

HEX -100充てる

このすべてが、これがあると言ってForthシステムにおける最も簡単なメモリ管理の形態です。これがどのように使用されるかの例は、 'BUFFER'という単語の定義に見ることができます:

:バッファ:(n - )CREATE ALLOT;

'BUFFER:'は辞書に新しい名前を作成します(作成すると、名前のためにスペースを作っています)。名前の直後にnバイトのメモリが割り当てられ、Forthシステムの関連するハウスキーピングバイトメモリは今

を終了

MARKERのFOOの\マークHEX 2000 BUFFER:IN_BUFFER

今、私たちは8Kを持っているが、我々はちょうどタイプという名前のメモリのブロックを割り当てるようになりましたので

を使用バイトバッファc alled IN_BUFFER。 Standard Forthでそのスペースを再利用したい場合、FOOと入力すると、FOOの後に辞書に割り当てられたものすべてがForthシステムから削除されます。

ただし、一時的なメモリスペースが必要な場合は、「ここ」の上のすべてを自由に使用できます!

だから、あなたは、単にアドレスを指し、あなたがこれを好きにしたい場合は、それを使用することができます

:MYMEMORYここに200 +を。上記に未割り当てられたメモリへ\ MYMEMORY点

     \ MYMEMORY moves with HERE. be aware. 

MYMEMORY HEX 1000年ERASE \動的メモリ割り当てが解除を引き起こす可能性がある場合ゼロ

フォースは、典型的には、高性能組み込みアプリケーションのために使用されているの2Kバイトでそれを埋めます信頼できるコードなので、ALLOTを使用する静的割り当てが優先されました。しかし、より大きなシステムでは、ヒープを持っており、ALLOCATE使用し、無料で、我々はC.

BF

+0

私はそれを他の目的のためにALLOTを使用して追加し、次に新しい単語や変数の断片的な割り当ては、UNIXの旧式のブレーク機構と似ています。 –

1

にmalloc関数などを使用するようにあなたが別の世界に入るフォースでは多くのサイズを変更します。

Linux上のciforth(64ビットと仮定)のような一般的な方法では、スワップ空間(128Gバイトなど)と同じ大きさのリニアなメモリ空間を持つようにForthを設定できます。それはあなたの配列、リンクされたリスト、写真を何でも埋めることです。制限はありません。 Forthは、あなたが使い果たしたメモリを追跡するのに役立つポインタのみを提供します。無視してもかまいません。1994年の標準では、空きメモリ(PAD)に浮遊するスクラッチスペースを提供するという言葉さえあります。

malloc()free()のようなものがありますか?必ずしも数十キロバイトの小さなカーネルではありません。しかし、ファイルをallocateユーティリティでインクルードするだけで、ダイナミックメモリに使用するために2ギガバイトを確保することができます。

例として、私は現在tiffファイルを扱っています。典型的な140Mバイトの画像は、ここで進んでいる辞書から小さなチャンクを取ります。 ピクセルの行は変換され、圧縮解除されます。そのために私は動的メモリを使用するので、行の圧縮解除結果のスペースを割り当てます。私は別の変換のために結果が使い果たされたときに手動で再びフリーズしなければならない。それはcとは全く違う感じです。より多くの制御とより多くの危険があります。

あなたの住所などが分かっている場合は、データ構造にアクセスすることができます。あなたが紙の上にF7FFA1003を記入したとしても。別々の名前空間によってプログラムを安全にしようとすることは、Forthスタイルでは目立っていません。いわゆる語彙リスト(VOCABULARYも参照)はその方向に施設を提供します。