ガベージコレクション: 自動的メモリ管理を構成する理論と実装を積ん読していたので消化するために前に読んでたメモをとりあえず残す
第一章
- 動的なメモリ割り当てを利用することによって、コンパイル時に総サイズがわからないオブジェクトでも割り付けたり、開放したりすることができる
- 動的に割り付けたオブジェクトはヒープに保存される
- アクティベーションレコードとはなんぞ?(スタック内の割付らしい)
- スタックフレームという領域があるらしい(よくわからん)
- 静的割付(オブジェクトの名前をコンパイル時あるいはリンク時に決定するメモリ上の場所に束縛する方法)
- なぜヒープへの割付が重要か?
- オブジェクトのサイズを動的に決められる(配列の上限値をハードコードするとプログラムが壊れる恐れがある)
- 再帰的なデータ構造を定義できる(リスト、ツリー、マップなど)
- 新しく生成したオブジェクトを親の手続きに返せる(これによってファクトリーメソッドなどの技法を使える)
- 関数の値として別の関数を返せる(所謂クロージャやサスペンション←初めて聞いた)
- ヒープに割り付けたオブジェクトには参照を用いてアクセスする(ポインタ、ハンドル)
- ハンドルを利用することで、オブジェクトの再配置が容易になる
- 明示的解放(CでいうfreeやC++のdeleteなど)
- 手動で解放する場合はプログラミングエラーを犯すリスクが有る(エラーは2種類)
- 一つはメモリを解放するのが早すぎるエラーで、メモリへの参照が残っているのに誤って解放してしまうケース(このような参照を宙ぶらりんポインタと呼ぶ)
- 例: A ref B ref C
- Bを手動解放した場合にAはBへの参照が残り、Cは到達不能となり解放することもできなくなる
- 宙ぶらりんのポインタを検出する方法の一つにファットポインタがある
- ファットポインタには、ポインタが指しているオブジェクトとポインタ自身のバージョン番号を格納しておく
- 参照をたどるような操作の際には、必ずポインタに格納してあるバージョン番号が、オブジェクトのバージョンと一致していることをチェックする
- (この手法は、オーバーヘッドのため、デバッキングツールでしか使えないことが多い, また完全に信頼できる方法でもない)
- 二つめはメモリリーク
- 先程の例のように一箇所のメモリ解放の誤りが宙ぶらりんポインタ(A)とメモリリーク(C)の両方を引き起こしてしまうこともありうる
- 一つはメモリを解放するのが早すぎるエラーで、メモリへの参照が残っているのに誤って解放してしまうケース(このような参照を宙ぶらりんポインタと呼ぶ)
- スレッドセーフなデータ構造にアクセスするアルゴリズムでは、さまざまな問題に対処する必要がある(デッドロック、ライブロック、ABAエラー)
- ガベージコレクションは宙ぶらりんポインタが作られるのを防止する(オブジェクトが回収されるのは、到達可能なオブジェクトからのポインタが1つもなくなった時だけ)
- GCは原則的にすべてのごみを解放することを保証する(すなわち到達不能なオブジェクトは全て最終的にはGCによって回収される)
- 注意点は以下
- 追跡型GC(Tracing collection)が用いる「ごみ」の定義は、決定可能なものであり、二度とアクセスされないオブジェクトすべてがごみとみなされるわけではない
- GCの実装によっては、効率上の理由からオブジェクトの一部を回収しないことがあるということ
- ガベージコレクタのみがオブジェクトを解放するので、二重解放問題は生じない(解放に関するすべての決定はコレクタが行う)
- コレクタはヒープ内のオブジェクトの構造やオブジェクトにアクセスする可能性のあるスレッドに関するグローバルな情報を持っている
ガベージコレクションが望ましい理由は、コードを書くのが簡単になるということではない
- 簡単にはなるが、それよりも重要なのはガベージコレクションによってメモリ管理の問題がインターフェイスから切り離せるということ
- ガベージコレクションなしではメモリ管理の問題がプログラム中に散乱することになる
- ガベージコレクションは再利用性を改善する、これが様々な分野でほぼすべての近代的な言語で必須とされている理由
- ガベージコレクションはスペースリークが絶対にないという保証はできない
- なぜなら、データ構造が到達可能なまま際限なく大きくなる場合(キャッシュ等)ガベージコレクションでは解決できない
- さらに到達可能だが二度とアクセスされないような場合についても同様
GCに求められる要素
- 安全性
- 生きているオブジェクトの回収などを行わないこと
- スループット
- mark/cons比
- 完全性
- ヒープ中のごみがすべて回収されること, かなり難しい(常にそれが最適とは限らない)
- 並行GC中に新たにでたごみを浮遊ごみと呼ぶ(そのため、並行GCの文脈では完全性をすべてのごみがいずれは回収されることとしたほうが良いことになる)
- 即時性
- GCアルゴリズムによって異なる、ここでもまた時間と空間のトレードオフが導かれる
- 停止時間
- 安全性