2021-03-04

『オブジェクト指向入門 第2版』の9章を読んだ

第9章 メモリ管理

オブジェクト管理の形式には,

  • 静的
  • スタックベース
  • 自由

のモードが存在する.

静的なモードでは,最初にすべてのオブジェクトの領域を割り付ける.このモードでは,動的にオブジェクトを生成できず,再帰的ルーチンも使用できないという重大な限界がある.

スタックベースは,オブジェクトをLIFOの順序で割り付ける.Cの基本型などはこのモードが適用される.動的にオブジェクトを生成できるが,完全に凡庸的なデータ構造はサポートしない.

自由モード(ヒープベース)は,完全に動的なモードである.Cでは,malloc関数などでこのモードが適用されている.

どのように回収するか

オブジェクトは,メモリ管理の視点で以下のように分類できる.

  • オリジン
    システムのルートオブジェクトや,現在実行されているルーチンのエンティティにアタッチされている全てのオブジェクト
  • 届くところにあるオブジェクト
    オリジンから直接的,あるいは間接的に依存するオブジェクト
  • 届かないところにあるオブジェクト
    上記に当てはまらないオブジェクト

届かないところにあるオブジェクトは利用されない領域であり,その領域を自由に使えるように(解放)しなければならない.対処の仕方として,以下の手法が考えられる.

呑気なアプローチ

領域が十分に存在することにし,問題を無視する.小さなプログラムや,実行時間を厳密に計測しなければならないような限定的な場面では,この手法がとられることがある.

プログラマ制御による解放

プログラマが不必要になった領域を回収する.正しく実装されてさえいればうまくいくが,問題は正しく実装するのが非常に困難なことである.回収し損ねる(メモリリークが起こる)とシステムがクラッシュし,間違って回収すると不正参照(回収されてしまったオブジェクトへの参照を利用する)が起きてシステムがクラッシュする.

自動領域管理

回収を自動で行う.この方法として,参照カウントとガーベジコレクタがある.

参照カウントは,オブジェクト自身が別のオブジェクトから一切参照されていないとき,そのオブジェクトを回収する.つまり,参照関係を有効グラフ(頂点がオブジェクト,参照が辺)で表したとき,入次数が0である頂点(オブジェクト)を回収する.これには問題があり,閉路に含まれる頂点は回収されない.

ガーベジコレクタは,オリジンから到達可能なオブジェクトにマークをつけ,次に領域を走査してマークのない要素を回収する.回収が終わると,すべてのマークは消される.この方法は,安全(回収されたオブジェクトは全て届かないところにある)であり完全(届かないところにある全てのオブジェクトを回収する)である.

ちなみに,

  • 一切オブジェクトを回収しない -> 安全
  • 全てのオブジェクトを回収する -> 完全

である.

この操作は時間がかかる.そのため,領域が足りなくなったときにその都度操作を実行すると,システムは予告もなく一定時間停止することになる.これに比べれば,均一に遅い方が望ましい.

負荷を分散させる方法として,以下の手法が挙げられる.

  • コレクタの実行をある程度制御できるようにする.
  • 世代別回収
    オブジェクトの生存期間によって,領域の検査の頻度を変える.
  • アプリケーションとコレクタを並列に実行する