Loment
日本語

システム

LomentGC

Loment のプログラムがメモリを解放するとき、その仕事のすべてをコレクタに任せはしない。 確保が起きるあらゆる場所は、コンパイル時に四つの戦略のいずれかに割り当て られ —— runtime コレクタにどれだけ任されるかは、文書の中の主張ではなく、バイナリに 書き込まれた数値である。

論文を読む

はしご

最強から最弱へ。コンパイラは証明できる最も強い段を取る。より多くを証明すれば、 払うものは少ない。各段の値段は脚注に残すのではなく、その隣に書かれている。

L0 — 静的

アロケーションはリテラルのサイズであり、ポインタはロード、ストア、アトミックの 第一引数として丸ごと渡されるだけである。ヒープには決して到達しないので、回収すべき ものが何もない。値段:より大きなスタックフレーム。

L1 — 最終使用

同じ形だが、関数本体のトップレベルで宣言されるので、最後の使用が数えられる。 コンパイラは、その後の最も早い return の前に free を挿入する。 値段:早期 return の経路では挿入点を取り逃すことがあり、その経路は 一度漏れる。漏れであって、バグではない。

L2 — ブロックエポック

ループ本体の内側では、すべてのアロケーションは本体を決して出て行かないローカルである。 本体の終わりは、アロケータのフロントを巻き戻すことで、領域全体を一度に返す —— リストも走査もない。エポックはブロック構造と脱出から推論され、手で書かれるのでは ない。値段:本体内のアロケーションがひとつでも脱出すると、ブロック全体が 残らなければならない。

L3 — runtime

コンパイラが証明できなかったすべて。コレクタの全コスト。

三つの段階

プログラムは、自分が始めるファイルに一行書くことで、はしごをどこまで下ることを許すかを 選ぶ。

choose gc_manual

既定。何も自動では回収されず、プログラムが自分のメモリを管理する。一行も書かなければ これになる —— 既定とは、その設定が存在する前からの振る舞いであり、それはすべての設定が 従う規則である。

choose gc_auto

runtime コレクタが回収する: 正確なルートを持つマーク&スイープで、確保したバイト数に よって起動される。

choose gc_auto_alpha

四つの段すべてが有効なので、コレクタはコンパイル時の段が証明できなかったものだけを 見る —— そしてそれは適応的である。しきい値はライブセットに従い、空間トリガーを備えるので、 上限は arena の固定された割合ではない。

発見されるのではなく明示される限界。gc_auto では、トリガーは 固定の 32 KiB で、arena は 64 KiB なので、ライブセットがおよそ 32 KB を超える プログラムはやはり尽きる。その隔たりを埋めるのが、適応的コレクタと、 gc_auto_alpha の下の世代別コレクタの役目である。

L3 の内側

runtime の段も、ひとつのアルゴリズムではない。それは三つの歩みで成長し、それぞれが、 計測可能なプログラム上でその前のものを打ち負かさなければならなかった。

マーク&スイープ

ルートは正確である —— ルートテーブルはスロットのアドレスを保持する —— 一方で、ブロックの内部は保守的に扱われる。alloc が型を持たず、ブロックが 何を保持するかを何も記録しないからだ。

適応的な起動

固定のしきい値は、ライブセットがどれだけ大きくなるかを推測しなければならない。 適応的なものはそれを読む: ライブセットが二倍になったとき、あるいは空間が尽きかけたときに 回収する。

世代別

二つの世代を、オブジェクトの年齢ではなくアドレスで分ける —— 移動しない コレクタは、各マイナーコレクションの終わりにフロンティアを進めることで昇格させる。 カードテーブルとライトバリアが、古い世代から若い世代へのポインタを捉える。それによって 節約されるのはマーク&伝播のパスで、それが若い世代だけを覆うようになる。

なぜ成果物に残るのか

各ユニットは、gc_ladder を運ぶ形式オブジェクトをエクスポートする: 各段が取った alloc サイトの数と、合計。四つの数は合計に一致しなければならず、 二つの独立した検証器が、ソースを一行も読まずにその算術を照合する。だから 「このプログラムのメモリはどう管理されるか?」は、文書の中の主張ではなく、ビルド出力の中の 数値である。

何が主張され、何が主張されていないか。はしごは二度実装されている —— 参照実装のコンパイラとセルフホストのもの —— そして両者はバイト単位で一致しなければならない。 各段の背後の測定は、プロジェクト自身の判据、すなわち小さなプログラムから来ている。 コレクタは実ワークロードに対して走らされたことがなく、これはこの話を性能の主張として読む前に 知っておく価値がある。