web-dev-qa-db-ja.com

Goはどのようなガベージコレクションを使用しますか?

Goはガベージコレクションされた言語です。

http://golang.org/doc/go_faq.html#garbage_collection

ここでは、それはマークアンドスイープガベージコレクターであると述べていますが、詳細については掘り下げておらず、置き換えは作業中です...しかし、この段落はGoがリリースされてからあまり更新されていないようです。

まだマークアンドスイープですか?保守的ですか、それとも正確ですか?世代的ですか?

102
user1003432

Go 1.4+ガベージコレクターの計画:

  • ハイブリッド世界停止/並行コレクター
  • 10ミリ秒の期限によって制限される世界の一部
  • コンカレントコレクターの実行専用のCPUコア
  • 三色マークアンドスイープアルゴリズム
  • 非世代
  • 非コンパクト
  • 完全に正確
  • プログラムがポインタを移動している場合、わずかなコストがかかります
  • go 1.3 GCよりもレイテンシは低いが、スループットも低い可能性が高い

Go 1.1のGo 1.3ガベージコレクターの更新:

  • 同時スイープ(一時停止時間が短くなります)
  • 完全に正確

Go 1.1ガベージコレクター:

  • マークアンドスイープ(並列実装)
  • 非世代
  • 非コンパクト
  • ほとんど正確(スタックフレームを除く)
  • 世界を止める
  • ビットマップベースの表現
  • プログラムがメモリを割り当てていない場合のゼロコスト(つまり、ポインターのシャッフルはCと同じくらい高速ですが、GoコンパイラーはGCCなどのCコンパイラーほど高度ではないため、実際にはCよりやや遅くなります)
  • オブジェクトのファイナライザーをサポートします
  • 弱参照のサポートはありません

Go 1.0ガベージコレクター:

  • go 1.1と同じですが、ほとんど正確ではなく、ガベージコレクターは保守的です。保守的なGCは、[] byteなどのオブジェクトを無視できます。

GCを別のGCに置き換えることは議論の余地があります。例えば:

  • 非常に大きなヒープを除いて、世代別GCが全体的に高速になるかどうかは不明です
  • パッケージが「安全でない」ため、完全に正確なGCと圧縮GCの実装が困難になります
109
user811773

Go 1.8-2017年第1四半期、以下を参照

次のGo 1.5 concurrent Garbage Collectorは、gcが「ペース」できるようにすることを伴います。
ここに提案があります このペーパーで Go 1.5に合うかもしれませんが、Goのgcの理解にも役立ちます。

状態を確認できますbefore 1.5(Stop The World:STW)

Go 1.5より前は、Goはparallel stop-the-world(STW)コレクターを使用していました。
STWコレクションには多くの欠点がありますが、少なくとも予測可能で制御可能なヒープ成長動作があります。

https://40.media.tumblr.com/49e6556b94d75de1050c62539680fcf9/tumblr_inline_nr6qq8D9FE1sdck2n_540.jpg

(写真 GopherCon 2015 プレゼンテーション " Go GC:Go 1.5でのレイテンシー問題の解決 ")

STWコレクターの唯一のチューニングノブは、コレクション間の相対的なヒープ成長である「GOGC」でした。デフォルト設定の100%は、以前のコレクションの時点でヒープサイズがライブヒープサイズの2倍になるたびに、ガベージコレクションをトリガーしました。

https://docs.google.com/drawings/image?id=sLJ_JvGfPfPnojLlEGLCWkw&rev=1&h=113&w=424&ac=1

STWコレクターのGCタイミング。

Go 1.5では、並行コレクターが導入されました
これには、STWコレクションに比べて多くの利点がありますが、mは、ガベージコレクターの実行中にアプリケーションがメモリを割り当てることができるため、制御が難しくなります

https://40.media.tumblr.com/783c6e557b427a5c023520578740eb94/tumblr_inline_nr6qqpmaJx1sdck2n_540.jpg

(写真 GopherCon 2015 プレゼンテーション " Go GC:Go 1.5でのレイテンシー問題の解決 ")

同じヒープの増加制限を達成するには、ランタイムはガベージコレクションを早めに開始する必要がありますが、どれだけ早いかは多くの変数に依存し、その多くは予測できません。

  • コレクターの起動が早すぎると、アプリケーションが実行するガベージコレクションが多すぎて、CPUリソースが無駄になります。
  • コレクターの開始が遅すぎると、アプリケーションは必要な最大ヒープ成長を超えます。

並行性を犠牲にすることなく適切なバランスを達成するには、ガベージコレクターを慎重にペーシングする必要があります。

GCペーシングは、ヒープの成長とガベージコレクターが使用するCPUの2つの次元に沿って最適化することを目的としています。

https://docs.google.com/drawings/image?id=sEZYCf7Mc0E0EGmy4gho3_w&rev=1&h=235&w=457&ac=1

GCペーシングの設計は、4つのコンポーネントで構成されています。

  1. gCサイクルに必要なスキャン作業量の推定値、
  2. ヒープ割り当てがヒープの目標に達するまでに、ミューテーターが推定量のスキャン作業を実行するメカニズム
  3. ミューテーターがCPUバジェットを十分に活用していない場合のバックグラウンドスキャンのスケジューラー
  4. gCトリガーの比例コントローラー。

設計は、CPU時間とヒープ時間の2つの異なる時間のビューのバランスをとります

  • CPU時間は標準のウォールクロック時間に似ていますが、GOMAXPROCS倍速くなります。
    つまり、GOMAXPROCSが8の場合、毎秒8 CPU秒が経過し、GCは毎秒2秒のCPU時間を取得します。
    CPUスケジューラはCPU時間を管理します。
  • ヒープ時間の経過はバイト単位で測定され、ミューテーターが割り当てると前進します。

ヒープ時間とウォール時間の関係は、割り当て率に依存し、常に変化します。
ミューテーターは、ヒープの経過時間の管理を支援し、ヒープが目標サイズに達するまでに推定スキャン作業が完了するようにします。
最後に、トリガーコントローラーは、これら2つの時間のビューを結び付けるフィードバックループを作成し、ヒープ時間とCPU時間の両方の目標を最適化します。

31
VonC

これはGCの実装です。

https://github.com/golang/go/blob/master/src/runtime/mgc.go

ソースのドキュメントから:

GCは、ミューテータースレッドと同時に実行され、タイプアキュレート(正確)であり、複数のGCスレッドを並行して実行できます。書き込みバリアを使用するマークとスイープの同時実行です。それは非世代的でコンパクトではありません。割り当ては、P割り当て領域ごとに分離されたサイズを使用して行われ、一般的な場合のロックを排除しながら断片化を最小限に抑えます。

18
berdario

Go 1.8 GCは、 提案「STWスタックの再スキャンの排除」 で再び進化する可能性があります

Go 1.7の時点で、無限で潜在的に自明でないstop-the-world(STW)時間の残りの1つのソースは、スタックの再スキャンです。

Yuasaスタイルの削除書き込みバリア[Yuasa '90]Dijkstraスタイルの挿入書き込みを組み合わせたハイブリッド書き込みバリアに切り替えることにより、スタックの再スキャンの必要性を排除することを提案します。バリア[ダイクストラ'78]

予備実験では、これにより最悪のSTW時間を50µs未満に短縮が可能であり、このアプローチにより、STWマークの終端を完全に排除できることが示されています。

お知らせはこちら で、関連するソースコミットは d70b0fe 以前であることがわかります。

8
VonC

確かではありませんが、現在の(ヒント)GCはすでに並列のものであるか、少なくともWIPであると思います。したがって、stop-the-worldプロパティは適用されないか、近い将来に適用されません。おそらく他の誰かがこれをより詳細に明らかにすることができます。

2
jnml