Improve this page Github へのログインが必要です。 簡単な修正は、ここから fork、オンライン編集、pull request ができます。 大きな修正については、 通常の clone で行って下さい。 Page wiki 関連するWikiページを参照・編集 English このページの英語版(原文)

ガベージコレクション

D は完全にガベージコレクトされた言語です。 つまり、メモリを解放する必要は 全く必要ありません。必要なだけ確保して、あとはガベージコレクタが定期的に 使われていないメモリをプールへ戻します。

C/C++ プログラマは明示的なメモリ確保と解放に慣れていて、 ガベージコレクタの効率や利点については懐疑的なようです。 私は、 一からガベージコレクションを念頭に置いて書いたプロジェクトと、 既存のプロジェクトを GC を使うように方向転換した経験のどちらも持っていますが:

ガベージコレクションは万能薬ではありません。欠点もあります:

これらの制約に対するテクニックについては、 メモリ管理 の項で概要を述べています。

ガベージコレクションの動作について

GCは次のステップで動作しています:

  1. GCで確保された領域を指す ‘roots’ ポインタを全て列挙します。
  2. rootから指されている領域内から、 再帰的にGCメモリ領域内を指しているポインタを探索します。
  3. GCで割り当てられた領域のうち、 生きたポインタで指されていないことが分かった領域を全て解放します。
  4. 残ったメモリ領域のデータをコピーして使用領域をまとめる処理 (コピーGCと呼ばれます) が実行される可能性があります。

GCの管理下にあるオブジェクトと外部コードとの接続

GCは、以下の領域を探索の出発点(root)とします:

  1. staticデータセグメント
  2. 各スレッドのスタック
  3. std.gc.addRoot() か std.gc.addRange() で追加された領域

もしこの他に出発点とすべきオブジェクトが存在していたとしても、 コレクタはそのオブジェクトを発見できず、 メモリを解放してしまいます。

これが起きるのを避けるには、

ポインタとGC

Dでのポインタは、大きく分けて二種類に分類できます:一つは、 ガベージコレクタで管理されたメモリを指すもの、もう一つは、そうでないものです。 後者の例としては、C の malloc() を呼んで作られたポインタや、 C のライブラリが返すポインタ、 あるいは静的データやスタックへのポインタなどがあります。 これらのポインタに対しては、Cで合法な操作は全て実行できます。

しかしながら、 ガベージコレクタに管理されたポインタと参照には、 幾つかの制限があります。大きな制限ではありませんが、 ガベージコレクタの設計に最大限の柔軟性を与えるために課されています。

未定義な動作:

保証されている、実行してもよいこと:

実際のところ、 ほとんどの場合はポインタを使わずに済みます。 Dは大抵のポインタの使い道に置き換わる機能を用意しています。 例えばオブジェクトへの参照、動的配列、 そしてガベージコレクションです。 ポインタは、CのAPIとのインターフェイスとして使うためと、 あとは低レベル処理のために用意されているものです。

GCとうまくやって行くには

ガベージコレクションは、 メモリ解放に関する全ての問題を解決するわけではありません。 例えば、巨大なデータ構造へのアクセスルートが生きていれば、 例え実際には二度と参照されないとしても、GCはその領域を再利用できません。 この問題を回避するには、必要ないオブジェクトへの参照やポインタにはnullを セットしておく、というのが良い習慣です。

このアドバイスは、staticな参照かオブジェクトに埋め込まれた参照にのみ当てはまります。 スタック上の参照にnullを代入するのにはあまり意味はありません。 いずれ新しいスタックフレームで書き潰される領域なので、 GCはスタックトップより先は見に行きませんから。

オブジェクトのピン留めとMove GC

現在の D の実装は move GC を採用していませんが、 上に上げた規則を守っていれば move GC の実装も可能です。 オブジェクトをピン留めするのに特別な処理は必要ありません。Move GC は、 あいまいな参照がなく、その参照を更新可能なオブジェクトだけを移動します。 そのほかのオブジェクトは自動的にアドレスが固定されます。

GC を使う D の操作

コードの一部で、GCの起動を避けたいことがあるかもしれません。 以下が、GCによりメモリ割り当てを行う言語要素の一覧です:

参考文献