メモリ管理の設計は、オブジェクト指向言語の柔軟性と効率性にたいへん
影響を及ぼす。
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-'を名前の前に付けている幾つかの関数がある。
これらの関数は、システムのリソースあるいは環境のリストを返し、
動的なデバッグに有用である。
sys:gc [関数]
-
-
ガーベージコレクションを実行する。割り当てられている中で空いているワード数および全体のワード数
のリストを返す。
sys:gctime [関数]
-
-
3つの整数のリストを返す。1つは、GCを呼び出した回数。
2つは、セルをマーキングするために使用した時間(1ユニットに1/60秒)。
3つが、矯正(マーキングを外し、マージする)のために使用した時間。
sys:alloc size [関数]
-
-
ヒープに少なくともsizeワードのメモリを配置し、
実際に配置されたワード数を返す。
sys:newstack size [関数]
-
-
現在のスタックを廃棄し、sizeワードの新しいスタックを配置する。
sys:*gc-merge* [変数]
-
-
メモリ管理用のパラメータ。
*gc-merge*は、GCによりマージされずに残すヒープメモリの比率を示す。
このマージされない領域は、すぐにconsのような小さなセルに満たされる。
デフォルトの値は、0.3である。
この値を0.4のように大きくすると、マージされない空きヒープが40%であることを
示し、consのためには役立つが、実数ベクトルやエッジや面などのような大きなセル
の確保には、害を及ぼす。
sys:*gc-margin* [変数]
-
-
メモリ管理用のパラメータ。
*gc-margin*は、全体のヒープに対する空きヒープの比率を決定する。
メモリは、UNIXから獲得したものであるため、空き空間はこの比率より
小さくならない。
デフォルトは、0.25であり、GCの際に25%以上の
空き空間が維持されることを意味する。
sys:reclaim object [関数]
-
-
ごみとしてobjectを廃棄する。
そのオブジェクトは、他のどのオブジェクトからも絶対に参照されないことが
保証されなければならない。
sys:reclaim-tree object [関数]
-
-
objectから通過できるsymbolを除いてすべてのオブジェクトを矯正する。
sys:btrace num [関数]
-
-
Lispのスタックのnum番目の深さの情報をトレースして表示する。
sys:memory-report &optional strm [関数]
-
-
セルのサイズでソートしたメモリ使用のテーブルをstrmストリームに出力する。
sys:room output-stream [関数]
-
-
クラスで整列したメモリ配置の情報を出力する。
sys:address object [関数]
-
-
プロセスのメモリ空間内にあるobjectのアドレスを返す。
sys:peek [vector] address type [関数]
-
-
addressで指定されたメモリ位置のデータを読みだし、
それを整数として返す。
typeは、:char, :byte, :short, :long, :float, :doubleの内の1つである。
もし、vectorが与えられなかったなら、
そのアドレスは、UNIXの処理空間として扱われる。
例えば、Sunにおいてa.outのヘッダーは#x2000に置かれるため、
(sys:peek #x2000 :short)はmagic number(ふつうは#o403)を返す。
Solaris2は、ELFヘッダーを#10000に置くため、
(sys:peek #x10000 :long)が"ELF"を表現する文字列である
#xff454c46を返す。
もし、vectorが与えられたならば、それはforeign-stringであり、
アドレスはvectorの起点からのオフセットとして認識される。
(sys:peek "123456" 2 :short)は、"34"を表現する
short wordを返す。(#x3334(13108)である)
アドレス位置については十分注意すること。
short, integer, long. float, double wordを奇数アドレスから読み出すと、
"bus error"になる。
sys:poke value [vector] address value-type [関数]
-
-
valueをaddressで指定された位置に書き込む。
プロセスのメモリ空間内のどこでも書き込むことができるため、
特に注意をしなければならない。
プロセスの空間の外へ書き込んだなら、
確実に"segmentation fault"が発生する。
short, integer, long. float, double wordを奇数アドレスに書き込んだ
場合、"bus error"が発生する。
sys:list-all-chunks [関数]
-
-
配置されたすべてのヒープのchunkをリストアップする。
他に有用な実行関数はない。
sys:object-size obj [関数]
-
-
objからアクセス可能なセルとワードの数を計算する。
objから参照可能なすべてのオブジェクトが探索される。
そして、3つの数のリストが返される。
1つ目は、セルの数。2つ目は、これらのオブジェクトに論理的に配置されたワード数(
すなわち、ユーザーからアクセスできるワード数)。
3つ目は、物理的に配置されたワード数。
これは、ヘッダーとメモリ管理のための特別なスロットを含む。
探索は、symbolで停止する。すなわち、property-listあるいはprint-name stringのような
symbolから参照されるオブジェクトは、カウントされない。
2016-04-05