Next: , Previous: , Up: GNU Emacsの内部   [Contents][Index]


E.3 ガーベージコレクション

プログラムがリストを作成するときや、(ライブライのロード等により)ユーザーが新しい関数を定義する際には、そのデータは通常ストレージに配置されます。通常ストレージが少なくなるとEmacsはもっとメモリーを割り当てるようにオペレーティングシステムに要求します。シンボル、コンスセル、小さいベクター、マーカー等のような別のタイプのLispオブジェクトはメモリー内の個別のブロックに隔離されます(大きいベクター、長い文字列、バッファー、および他の特定の編集タイプは非常に巨大であり1つのオブジェクトにたいして個別のブロックが割り当てられて、小さな文字列は8kバイトのブロック、小さいベクターは4kバイトのブロックにパックされる)。

基本的なベクター以上のマーカー、オーバーレイ、バッファーのような多くのオブジェクトが、あたかもベクターであるかのように管理されています。対応するCデータ構造体にはunion vectorlike_headerフィールドが含まれ、そのメンバーsizeにはenum pvec_typeで列挙されたサブタイプ、その構造体が含むLisp_Objectフィールドの数に関する情報、および残りのデータのサイズが含まれます。この情報は、オブジェクトのメモリーフットプリントの計算に必要であり、ベクターブロックの繰り返し処理の際のベクター割り当てコードにより使用されます。

しばらくの間いくつかのストレージを使用して、(たとえば)バッファーのkillやあるオブジェクトを指す最後のポインターの削除によりそれを解放するのは非常に一般的です。この放棄されたストレージを再利用するためにEmacsはガーベージコレクター(garbage collector)を提供します。ガーベージコレクターは本質的には、いまだにLispプログラムからアクセス可能なすべてのLispオブジェクトを検索、マークすることにより動作します。これを開始するにはすべてのシンボル、それらの値と関連付けられている関数定義、現在スタック上にあるすべてのデータをアクセス可能であると仮定します。別のアクセス可能オブジェクトを介して間接的に到達できるすべてのオブジェクトもアクセス可能とみなされますが計算は“保守的”に行われるので、アクセス可能なオブジェクトの個数はいくらか過大に評価されるかもしれません。 accessible, but this calculation is done , so it may slightly overestimate how many objects that are accessible.

マーキングが終了してもマークされないオブジェクトはすべてガーベージ(garbage: ごみ)です。Lispプログラムかユーザーの行為かに関わらず、それらに到達する手段はもはや存在しないので参照することは不可能です。誰もそれを失うことはないので、それらのスペースは再利用されることになります。ガーベージコレクターの2つ目ののフェーズ(sweep: スイープ、一掃)ではそれらの再利用を計らいます(がマーキングは“保守的”に行われるのですべてのスイープが一度ですべての未使用オブジェクトをガーベージコレクトする保証はない)。

スイープフェーズは将来の割り当て用に、シンボルやマーカーと同様に未使用のコンスセルをフリーリスト(free list)上に配置します。これはアクセス可能な文字列は少数の8kブロックを占有するように圧縮して、その後に他の8kブロックを解放します。ベクターブロックから到達不可能はベクターは可能なかぎり最大のフリーエリアを作成するために統合して、フリーエリアが完全な4kブロックに跨がるようならブロックは解放されます。それ以外ならフリーエリアはフリーリスト配列に記録されます。これは各エントリーが同サイズのエリアのフリーリストに対応します。巨大なベクター、バッファー、その他の巨大なオブジェクトは個別に割り当てと解放が行われます。

Common Lispに関する注意: 他のLispと異なりGNU Emacs Lispはフリーリストが空のときにガーベージコレクターを呼び出さない。かわりに単にオペレーティングシステムに更なるストレージの割り当てを要求して、gc-cons-thresholdバイトを使い切るまで処理を継続する。

これは特定のLispプログラムの範囲の実行直前に明示的にガーベージコレクターを呼び出せば、その範囲の実行中はガーベージコレクターが実行されないだろうと確信できることを意味する(そのプログラム範囲が2回目のガーベージコレクションを強制するほど多くのスペースを使用しないという前提)。

Command: garbage-collect

このコマンドはガーベージコレクションを実行して使用中のスペース量の情報をリターンする(前回のガーベージコレクション以降にgc-cons-thresholdバイトより多いLispデータを使用した場合には自然にガーベージコレクションが発生することもあり得る)。

garbage-collectは使用中のスペース量の情報をリストでリターンする。これの各エントリーは‘(name size used)’という形式をもつ。このエントリーでnameはそのエントリーが対応するオブジェクトの種類を記述するシンボル、sizeはそれが使用するバイト数、usedはヒープ内で生きていることが解ったオブジェクトの数、オプションのfreeは生きていないがEmacsが将来の割り当て用に保持しているオブジェクトの数。全体的な結果は以下のようになる:

((conses cons-size used-conses free-conses)
 (symbols symbol-size used-symbols free-symbols)
 (strings string-size used-strings free-strings)
 (string-bytes byte-size used-bytes)
 (vectors vector-size used-vectors)
 (vector-slots slot-size used-slots free-slots)
 (floats float-size used-floats free-floats)
 (intervals interval-size used-intervals free-intervals)
 (buffers buffer-size used-buffers)
 (heap unit-size total-size free-size))

以下は例:

(garbage-collect)
      ⇒ ((conses 16 49126 8058) (symbols 48 14607 0)
                 (strings 32 2942 2607)
                 (string-bytes 1 78607) (vectors 16 7247)
                 (vector-slots 8 341609 29474) (floats 8 71 102)
                 (intervals 56 27 26) (buffers 944 8)
                 (heap 1024 11715 2678))

以下は各要素を説明するためのテーブル。最後のheapエントリーはオプションであり、背景にあるmalloc実装がmallinfo関数を提供する場合のみ与えられることに注意。

cons-size

コンスセルの内部的サイズ(sizeof (struct Lisp_Cons))。

used-conses

使用中のコンスセルの数。

free-conses

オペレーティングシステムから取得したスペースにあるがカレントで未使用のコンスセルの数。

symbol-size

シンボルの内部的サイズ(sizeof (struct Lisp_Symbol))。

used-symbols

使用中のシンボルの数。

free-symbols

オペレーティングシステムから取得したスペースにあるがカレントで未使用のシンボルの数。

string-size

文字列ヘッダーの内部的サイズ(sizeof (struct Lisp_String))。

used-strings

使用中の文字列ヘッダーの数。

free-strings

オペレーティングシステムから取得したスペースにあるがカレントで未使用の文字列ヘッダーの数。

byte-size

これは利便性のために使用されるものでsizeof (char)と同じ。

used-bytes

すべての文字列データの総バイト数。

vector-size

長さ1のベクターのヘッダーを含めたバイトサイズ。

used-vectors

ベクターブロックから割り当てられたベクターブロック数。

slot-size

ベクタースロットの内部的なサイズで常にsizeof (Lisp_Object)と等しい。

used-slots

全使用済みベクターのスロット数。スロット数にはプラットフォームに応じてベクターのヘッダーに由来する一部、またはすべてのオーバーヘッドが含まれるかもしれない。

free-slots

すべてのベクターブロックのフリースロットの数。

float-size

浮動小数点数オブジェクトの内部的なサイズ(sizeof (struct Lisp_Float))。(ネイティブプラットフォームのfloatdoubleと混同しないこと。)

used-floats

使用中の浮動小数点数の数。

free-floats

オペレーティングシステムから取得したスペースにあるがカレントで未使用の浮動小数点数の数。

interval-size

インターバルオブジェクト(interval object)の内部的なサイズ(sizeof (struct interval))。

used-intervals

使用中のインターバルの数。

free-intervals

オペレーティングシステムから取得したスペースにあるがカレントで未使用のインターバルの数。

buffer-size

バッファーの内部的なサイズ(sizeof (struct buffer))。(buffer-size関数がリターンする値と混同しないこと。)

used-buffers

使用中のバッファーオブジェクトの数。これにはユーザーからは不可視のkillされたバッファー、つまりリストall_buffers内のバッファーすべてが含まれる。

unit-size

ヒープスペースを計る単位であり常に1024バイトと等しい。

total-size

unit-size単位での総ヒープサイズ。

free-size

unit-size単位でのカレントで未使用のヒープスペース。

純粋スペース(純粋ストレージを参照)内にオーバーフローがあり、かつEmacsが(時代遅れとなった)unexecメソッド(Emacsのビルドを参照)を使用してダンプされていたら、この場合は実際にガーベージコレクションを行うことは不可能なのでgarbage-collectnilをリターンする。

User Option: garbage-collection-messages

この変数が非nilならEmacsはガーベージコレクションの最初と最後にメッセージを表示する。デフォルト値はnil

Variable: post-gc-hook

これはガーベージコレクションの終わりに実行されるノーマルフック。ガーベージコレクションはこのフックの関数の実行中は抑制されるので慎重に記述すること。

User Option: gc-cons-threshold

この変数の値は別のガーベージコレクションをトリガーするために、ガーベージコレクション後にLispオブジェクト用に割り当てなければならないストレージのバイト数。特定のオブジェクトタイプに関する情報を取得するために、garbage-collectがリターンした結果を使用できる。バッファーのコンテンツに割り当てられたスペースは勘定に入らない。

threshold(しきい値)の初期値はGC_DEFAULT_THRESHOLDであり、これはalloc.c内で定義されている。これはword_size単位で定義されているので、デフォルトの32ビット設定では400,000、64ビット設定では800,000になる。大きい値を指定するとガーベージコレクションの頻度が下る。これはガーベージコレクションにより費やされる時間を減少させる(のでガーベージコレクションが滅多に発生しないサイクル間ではLispプログラムは高速に実行されるだろう)が、メモリーの総使用量は増大する。大量のLispデータを作成するプログラムにおいて、特に高速な実行を要する場合にはこれを行いたいと思うかもしれない。ただしわたしたちは長期間に渡るthresholdの増加は推奨しないし、満足できる速さでプログラムが実行できる以上にの値には決してセットしないことをお勧める。必要以上に大きいthresholdを用いることによってシステムレベルでメモリーが逼迫する可能性があること、更にガーベージコレクションの各サイクルにより時間を要することにもなるので避けるべきである。

GC_DEFAULT_THRESHOLDの1/10まで下げた小さな値を指定することにより、より頻繁にガーベージコレクションを発生させることができる。この最小値より小さい値は後続のガーベージコレクションで、garbage-collectがthresholdを最小値に戻すときまでしか効果をもたないだろう。

User Option: gc-cons-percentage

この変数の値はガーベージコレクション発生するまでのコンス(訳注: これはgc-cons-thresholdgc-cons-percentageの‘-cons-’のことで、これらの変数が定義されているalloc.c内ではLisp方言での‘cons’をより一般化したメモリー割り当てプロセスのことを指す模様)の量をカレントヒープサイズにたいする割り合いで指定する。この条件とgc-cons-thresholdを並行して適用して、条件が両方満足されたときだけガーベージコレクションが発生する。

ヒープサイズ増加にともないガーベージコレクションの処理時間は増大する。したがってガーベージコレクションの頻度割合を減らすのが望ましいことがある。

gc-cons-thresholdと同じように必要以上に増加させず、長期間増加したままにしないこと。

gc-cons-thresholdおよびgc-cons-percentageを介した制御は単なる近似です。たとえEmacsが定期的にしきい値(threshold)の枯渇をチェックしていても、効率上の理由によりヒープ、またはgc-cons-thresholdgc-cons-percentageの変更のそれぞれにたいして、その後即座にガーベージコレクターをトリガーする訳ではありません。更にしきい値計算の効率化のために、Emacsはヒープ内のカレントでアクセス可能なオブジェクトを計数してヒープサイズを近似します。

garbage-collectがリターンする値はデータ型に分類されたLispデータのメモリー使用量を記述します。それとは対照的に関数memory-limitはEmacsがカレントで使用中の総メモリー量の情報を提供します。

Function: memory-limit

この関数はEmacsがカレントで使用中の仮想メモリーの総バイト数を1024で除してリターンする。あるアクションがメモリー使用にどのよな効果を及ぼすかについて概観を得るためにこの関数を使用できる。

Variable: memory-full

この変数はLispオブジェクト用のメモリーが不足に近い状態ならt、それ以外ならnil

Function: memory-use-counts

これはそのEmacsセッションで作成されたオブジェクト数をカウントしたリスト。これらのカウンターはそれぞれ特定の種類のオブジェクトを数える。詳細はドキュメント文字列を参照のこと。

Function: memory-info

この関数はシステムメモリーのトータル量とフリーな量をリターンする。サポートされないシステムでは値はnilかもしれない。

default-directoryがリモートホスト上を指している場合には、そのホストのメモリー情報がリターンされる。

Variable: gcs-done

この変数はそのEmacsセッションでそれまでに行われたガーベージコレクションの合計回数。

Variable: gc-elapsed

この変数はそのEmacsセッションでガーベージコレクションの間に費やされた経過時間を浮動小数点数で表した総秒数。

Function: memory-report

Emacsがどこでメモリーを使用(種々の変数、バッファー、キャッシュ)しているかが確認できれば便利なときがあるかもしれない。このコマンドはその概要を提供する(‘"*Memory Report*"’という)バッファーを新たにオープンすることに加えて、“最大”のバッファーおよび変数をリストする。

ここでのデータは変数サイズを計算する同質的な方法が究極的に存在しないために近似値である。たとえば2つの変数がデータ構造を共有するかもしれず、その場合には2回カウントされるだろうが、このコマンドは依然としてEmacsが使用する有用なメモリーの高レベル概要を与えるかもしれない。


Next: スタックに割り当てられたオブジェクト, Previous: 純粋ストレージ, Up: GNU Emacsの内部   [Contents][Index]