![]() |
|
メモリ管理の設計は、オブジェクト指向言語の柔軟性と効率性にたいへん 影響を及ぼす。 Euslispは、フィボナッチバディ法を基本に統一した方法で オブジェクトをメモリに割り当てる。 この方法は、chunkと呼ばれる大きなメモリのプールを小さなセルに分割する。 それぞれのセルは、サイズが等しくなく、フィボナッチ数がそれぞれ割り当てられる。 chunkメモリは、symbol, cons, string, float-vectorなどのような 様々な型のオブジェクトのための同次なデータ容器である。 それらのサイズはchunkと一致する長さである。 chunkは、固定、動的、再配置可能、交替可能などのような どんな特別な属性も持っていない。 EusLispのヒープメモリは、chunkの集合である。そして、 ヒープはUNIXより新しいchunkを得ることにより動的に拡張することができる。 拡張は、動作中に自動的に発生するかあるいはユーザーがsystem:alloc関数を 呼び出すことにより発生する。 自動的に処理されるとき、使用可能なメモリサイズは合計のヒープサイズの 約25%に保つ。この比率は、sys:*gc-margin*パラメータに0.1から0.9までの値を設定 することにより変更することができる。
すべてのヒープメモリを使いきったとき、mark-and-sweep型のガーベージコレクション(GC) を始める。 ルート(パッケージ,クラスやスタック)からアクセス可能なセルは, 同じアドレスのままである。 他のアクセス不可能なセルは、矯正されfree-listsにリンクされる。 GCの間にコピーやコンパクト化は発生しない。 ガーベージされるセルが矯正されるとき、その隣接セルがfreeかどうかチェックされる。 そして、できるだけ大きなセルを構成するようにマージされる。 しかしながら、このマージは、ときどき意味の無いものになる。 なぜなら、もっとも頻繁に呼び出されるメモリアロケータであるconsが、 そのマージされたセルを最も小さなセルに分割することを要求するからである。 したがって、Euslispはconsの高速化のためにマージされないある特定の量の ヒープを残すことを許可している。 この比率は、sys:*gc-merge*パラメータによって決定される。その値のデフォルトは 0.3である。 sys:*gc-merge*に大きな値を設定することにより、マージされないヒープを多く残す。 これは、consが要求されるとき、buddy-cellの分割が滅多に起こらないので、consの性能を改善する。 これは、また3次元ベクトルのような相対的に小さなセルのアロケーションについて すべて成り立つ。
sys:gcは、明示的にガーベージコレクターを呼び出す。 そして、ヒープに配置された空いているワード数と全体のワード数(バイト数ではない)を示す2つの整数の リストを返す。
もし、実行中に"fatal error: stack overflow"が報告され、 そのエラーが無限ループあるいは再帰処理によるものでないと確信するならば、 sys:newstackでLispのスタックの大きさを拡張すれば回避できる。 sys:newstackを設定する前には、resetを実行しなければならない。 なぜなら、 スペシャルバインドとunwind-protectの整理用の書式が 現在のスタックの中からすべて捨てられるためである。
新しいスタックが配置された後、オープニングメッセージを表示するところから 実行を始める。 デフォルトのスタックサイズは、16Kwordである。 Lispのスタックは、システムのスタックと別物である。 前者は、ヒープ上に配置され、後者は、オペレーティングシステムによって スタックセグメント内に配置される。 もし、"segmentation fault"エラーが発生したならば、システムのスタックが小さいことに より発生したことが考えられる。 cshのコマンドlimitで、システムのスタックサイズを増加することにより、 解決できる可能性がある。
sys:reclaimとsys:reclaim-tree関数は、オブジェクトにより占有されているセルを メモリマネージャーに戻す。そのため、ガーベージコレクションを呼び出すことなしに その後も再使用をすることができる。 しかし、それらのセルが他のセルから参照されていないことが確実でなければならない。
memory-reportとroom関数は、メモリの使用に関する統計を セルのサイズやクラスによりソートして表示する。
addressは、オブジェクトのバイト換算したアドレスを返す。 このアドレスはプロセスに独自のものであるから、 この関数はハッシュテーブルが使用するハッシュ関数に有用である。
peekとpokeは、メモリから直接データを読み書きできる関数である。 アクセスする型は、:char, :byte, :short, :long, :integer, :float, :double のどれかにすべきである。 例えば、(SYS:PEEK (+ 2 (SYS:ADDRESS '(a b))) :short)は、 consセルのクラスID(ふつう1である)を返す。
'list-all-'を名前の前に付けている幾つかの関数がある。 これらの関数は、システムのリソースあるいは環境のリストを返し、 動的なデバッグに有用である。
アドレス位置については十分注意すること。 short, integer, long. float, double wordを奇数アドレスから読み出すと、 "bus error"になる。