Richard L. Hudson(Rick)は、Java、C#、Goなどの静的型付き言語でのガベージコレクションを可能にするTrain、Sapphire、Mississippi Deltaアルゴリズムの発明やGCスタックマップなど、メモリ管理の仕事で有名です。 彼の著者として、言語ランタイム、メモリ管理、マルチスレッド、同期、メモリモデル、トランザクションメモリに関するドキュメントが公開されました。 現在、リックはGoogleのGoチームのメンバーであり、ガベージコレクターとランタイムの問題に取り組んでいます。
経済学では、あるプロセスが別のプロセスを強化するときに「クローズドサイクル」という概念があり、それによって最初のプロセスが強化されます。 歴史的に、コンピューターの世界では、このような「閉ループ」はハードウェアとソフトウェアの開発の間にありました。 プロセッサはより高速になり、より強力なソフトウェアの作成に貢献しました。これにより、一般にプロセッサとコンピュータの処理速度がさらに向上しました。 このサイクルは、ムーア法が機能しなくなった2004年頃まで機能しました。
現在、トランジスタの数が2倍に増えても、プログラムが2倍に高速化されるわけではありません。 より多くのトランジスタ==より多くのプロセッサコアですが、プログラムはより多くのコアを使用するほど進化していません。 最新のプログラムはマルチコアを最大限に使用していないため、プロセッサを開発する人はコアを追加しません。 サイクルは死んでいます。
Goの長期的な使命は、このサイクルを再開して、より多くの並行プログラムを世界に提供することです。 短期的な使命は、グローバルな開発者コミュニティによる囲adoptionの採用を増やすことです。 そして、現時点でのGoに関する最大の不満の1つは、ガベージコレクターの一時停止が長すぎることです。
チームが最初に問題を取り上げたとき、エンジニアとしての最初の反応は問題自体を解決するのではなく、次のような回避策を見つけることであると冗談で言いました。
- コンピュータにアイトラッキングを追加し、誰も見ていないときにガベージコレクターを実行する
- ガベージコレクションフェーズ中にネットワークスタンバイアイコンを表示し、ガベージコレクタを一時停止のせいではなく、ネットワークの遅延などを非難する
しかし、ラスコックスは、何らかの理由でこれらのアイデアをぶどうの木に投げかけ、Goのガベージコレクターを実際に改善することにしました。 GCの一時停止を減らすアルゴリズムを思いつきましたが、プログラムは少し遅くなります。 Goのプログラムは、ガベージコレクションフェーズで保証された低い休止時間と引き換えに、少し遅くなります。
どの遅延を区別できますか?
- ナノ秒:グレースホッパーは時間と距離を比較しました。 ナノ秒は11.8インチです。
- マイクロ秒:5.4マイクロ秒は、真空中で光が1マイル進む時間です。
- ミリ秒:
- 1:SSDを使用した1MBの順次読み取り。
- 20:回転ディスクから1MBを読み取ります。
- 50:知覚の閾値(反応の閾値)
- 50+:さまざまなネットワーク遅延
- 300:点滅する目
それでは、1ミリ秒でどれだけのガベージコレクションの作業を行うことができますか?
Java GCとGo GC
行く:
- 千のゴルーチン
- チャンネル同期
- ランタイムは、通常のコードのような機能を使用してGoで記述されています
- 空間的局所性制御(構造、内部ポインター(&foo.field)を埋め込むことができます)
Java:
- 多数のJavaスレッド
- オブジェクト/ロックを介した同期
- ランタイムはCで書かれています
- ポインターを介してリンクされたオブジェクト
ここでの最大の違いは、空間的な局所性の問題です。 Javaでは、すべてがポインターであり、Goでは、構造を別の構造に埋め込むことができます。 多くのレベルへのリンクを深く調べなければならない場合、ガベージコレクターにとって多くの問題が発生する可能性があります。
ガベージコレクターの基本
ガベージコレクターの動作の簡単な例を次に示します。 通常、2つのフェーズで構成されます。
- スキャンフェーズ:ヒープ上のどの要素に到達できるかを判断します。 これには、スタック上のポインタ、レジスタ、グローバル変数、そしてヒープ上のポインタが含まれます。
- マーキング段階:ポインターの列を通過します。 プログラムの実行中にオブジェクトを達成可能としてマークします。 ガベージコレクターの観点から見ると、この段階でポインターがまったく変わらないように、「世界を止める」のが最も簡単な方法です。 ポインターが常に変化しているため、真の並列ガベージコレクターを作成することは非常に困難です。 プログラムは、いわゆる「書き込みバリア」を使用して、このオブジェクトをキャプチャする必要がないことをガベージコレクターに伝えます。 ただし、実際には、障壁を記録すると、「世界を止める」よりもさらに悪い結果が生じる可能性があります。
ガベージコレクターに行く
Goの新しいガベージコレクタアルゴリズムは、書き込みバリアと短い一時停止の組み合わせを使用して、「世界を停止します」。 そのフェーズは次のとおりです。
Go 1.4のガベージコレクターは次のとおりです。
そして、これがGo 1.5の外観です。
「世界を止める」ための一時停止はずっと短いことに注意してください。 パラレルガベージコレクターの実行中は、プロセッサの25%を使用します。
テスト結果は次のとおりです。
Goの以前のバージョンでは、ガベージコレクターの一時停止は一般にはるかに長く、ヒープサイズが大きくなるにつれて長くなりました。 Go 1.5では、ガベージコレクターの一時停止が1桁以上小さくなりました。
数値を近づけると、ヒープサイズとGC一時停止の継続時間との間にまだ弱い正の相関があることがわかります。 しかし、彼らはその理由を知っており、Go 1.6で修正される予定です。
新しいアルゴリズムではパフォーマンスがわずかに低下しますが、ヒープが増加するにつれてこの低下は減少します。
未来に目を向ける
Goでガベージコレクションの一時停止が問題ではなくなったことを人々に知らせてください。 将来に目を向けると、ガベージコレクタを不明瞭にして、一時停止をさらに短くし、パフォーマンスを向上させ、予測可能性を高めることを計画しています。 彼らはこの妥協点で最高のバランスを見つけたいと思っています。 Go 1.6の開発はフィードバックに依存するため、コミュニティからのフィードバックを非常に楽しみにしています。
新しいガベージコレクターにより、Goは手動メモリ言語のより優れた代替品になります。
参照資料
スライド: talks.golang.org/2015/go-gc.pdf
Goのガベージコレクターの詳細
1.5同時ガベージコレクターペーシングを実行する
Go 1.4+ガベージコレクション(GC)計画とロードマップ