> Source: https://www.ymotongpoo.com/works/goblog-ja/go15gc/


# Go GC：低レイテンシとシンプルさを優先する

[Go GC: Prioritizing low latency and simplicity](https://go.dev/blog/go15gc) by Richard Hudson

## セットアップ

Goは2015年のためだけでなく、2025年以降のためのガベージコレクタ(GC)を構築しています。
今日のソフトウェア開発を支え、今後10年にわたって新しいソフトウェアやハードウェアとともにスケールしていくGCです。
そのような未来には、stop-the-worldのGC一時停止の入り込む余地はありません。これはGoのような安全で安心な言語が
より広く使われる上での障害となってきました。

この未来の最初の姿であるGo 1.5は、1年前に設定した10ミリ秒という目標を大きく下回るGCレイテンシを達成しています。
[Gopherconでの講演](/talks/2015/go-gc.pdf)ではいくつかの印象的な数値を発表しました。
このレイテンシの改善は大きな注目を集めています。Robin Verlangenさんのブログ記事
「[Billions of requests per day meet Go 1.5](https://medium.com/@robin.verlangen/billions-of-request-per-day-meet-go-1-5-362bfefa0911)」は、
エンドツーエンドの結果をもって私たちの方向性の正しさを裏付けています。また
[Alan Shreveさんの本番サーバーのグラフ](https://twitter.com/inconshreveable/status/620650786662555648)と、
その「素晴らしい85%削減」というコメントには特に胸を躍らされました。

今日では16ギガバイトのRAMはわずか100ドルで手に入り、CPUには多数のコアが搭載され、それぞれのコアが複数の
ハードウェアスレッドを持っています。10年後にはこうしたハードウェアも時代遅れに見えることでしょうが、
今日Goで構築されているソフトウェアは、拡大するニーズや次に来る大きな変化に対応してスケールしていく必要があります。
ハードウェアがスループットを高める力を提供してくれる以上、Goのガベージコレクタは低レイテンシを優先し、
たった一つのつまみでチューニングできるように設計されています。Go 1.5はこの道を進む最初の大きな一歩であり、
この最初の一歩はGoとGoが最も得意とするアプリケーションの両方に、これから先ずっと影響を与え続けるでしょう。
この記事では、Go 1.5のコレクタのために私たちが行ったことの概要を説明します。

## 肉付け

次の10年のためのガベージコレクタを作るにあたって、私たちは数十年前のアルゴリズムに目を向けました。
Goの新しいガベージコレクタは並行(concurrent)・三色(tri-color)・マークアンドスイープ(mark-sweep)方式のコレクタで、
これは[1978年にDijkstraによって最初に提案された](http://dl.acm.org/citation.cfm?id=359655)アイデアです。
これは今日の多くの「エンタープライズ」グレードのガベージコレクタとは意図的に異なる道を選んだものであり、
現代のハードウェアの特性と現代のソフトウェアが求めるレイテンシ要件によく合っていると私たちは考えています。

三色コレクタでは、すべてのオブジェクトは白・灰色・黒のいずれかの色を持ち、ヒープはオブジェクトがつながった
グラフとして扱われます。GCサイクルの開始時点では、すべてのオブジェクトは白です。GCはまず、グローバル変数や
スタック上のものなど、アプリケーションから直接アクセスできるオブジェクトである _ルート_ をすべて訪れ、
それらを灰色に塗ります。次にGCは灰色のオブジェクトを一つ選んで黒に塗り、そのオブジェクトの中に他のオブジェクトへの
ポインタがないかをスキャンします。このスキャンで白いオブジェクトへのポインタが見つかると、そのオブジェクトは
灰色に塗られます。このプロセスは、灰色のオブジェクトがなくなるまで繰り返されます。この時点で、白いオブジェクトは
到達不能であることがわかり、再利用できるようになります。

これらすべての処理は、_ミューテータ_ と呼ばれるアプリケーションと並行して行われ、コレクタが動作している間も
ミューテータはポインタを変更し続けます。そのため、ミューテータは「黒いオブジェクトが白いオブジェクトを指すことはない」
という不変条件を維持しなければなりません。そうしなければ、ガベージコレクタはすでに訪問済みのヒープの一部に
新たに組み込まれたオブジェクトを見失ってしまいます。この不変条件を維持する役目を担うのが _ライトバリア_ です。
これは、ヒープ内のポインタが変更されるたびにミューテータによって実行される小さな関数です。Goのライトバリアは、
新たに到達可能になったオブジェクトが現在白であれば、それを灰色に塗ります。これにより、ガベージコレクタがいずれ
そのオブジェクトのポインタをスキャンすることが保証されます。

すべての灰色のオブジェクトを見つけ終えたタイミングを判断するのは微妙な問題で、ミューテータのブロックを
避けようとすると、コストが高く複雑になりがちです。物事を単純に保つため、Go 1.5はできる限り多くの作業を
並行して行い、その後に短時間だけstop-the-worldを行って、灰色のオブジェクトになりうるすべての発生源を
検査します。この最後のstop-the-worldに必要な時間と、このGCが行う作業の総量との間の最適なバランスを
見つけることが、Go 1.6での大きな課題です。

もちろん、詳細に踏み込むほど厄介な問題が出てきます。GCサイクルはいつ開始すべきか。その判断には
どのような指標を使うべきか。GCはGoのスケジューラとどのように連携すべきか。スタックをスキャンするのに
十分な時間、ミューテータのスレッドをどうやって一時停止させるか。白・灰色・黒をどのように表現すれば、
灰色のオブジェクトを効率よく見つけてスキャンできるか。ルートがどこにあるかをどうやって知るか。
オブジェクトの中のどこにポインタがあるかをどうやって知るか。メモリの断片化をどうやって最小化するか。
キャッシュ性能の問題にどう対処するか。ヒープはどれくらいの大きさにすべきか。こうした問いは尽きることがなく、
アロケーションに関するもの、到達可能なオブジェクトの発見に関するもの、スケジューリングに関するものなど
様々ですが、その多くはパフォーマンスに関わるものです。これらの各分野についての低レベルな議論は、
この記事の範囲を超えています。

もっと高い視点で見ると、パフォーマンス上の問題を解決する一つのアプローチは、問題ごとに一つずつGCのつまみを
追加していくことです。プログラマはそれらのつまみをひねりながら、自分のアプリケーションに適した設定を
探すことになります。この方法の欠点は、毎年1つか2つの新しいつまみが10年も追加され続けると、最終的には
「GCのつまみひねり雇用対策法」のような状態になってしまうことです。Goはそのような道を選びません。
代わりに、GOGCというたった一つのつまみを提供します。この値は、到達可能なオブジェクトのサイズに対する
ヒープ全体のサイズを制御します。デフォルト値の100は、直前のコレクション終了時点での到達可能なオブジェクトの
サイズよりも、ヒープ全体のサイズが100%大きい(つまり2倍である)ことを意味します。200であれば、
到達可能なオブジェクトのサイズよりヒープ全体のサイズが200%大きい(つまり3倍である)ことを意味します。
GCに費やされる合計時間を減らしたいのであればGOGCを大きくし、メモリを減らす代わりにGCの時間が増えてもよいので
あればGOGCを小さくしてください。

さらに重要なことに、次世代のハードウェアでRAMが倍増したときは、GOGCを単純に2倍にするだけでGCサイクルの回数を
半分にできます。一方で、GOGCは到達可能なオブジェクトのサイズを基準にしているため、到達可能な
オブジェクトを2倍にして負荷を2倍にしても、再チューニングは必要ありません。アプリケーションはただスケール
するだけです。さらに、何十個ものつまみを継続的にサポートする手間から解放されることで、ランタイムチームは
実際の顧客アプリケーションからのフィードバックに基づいてランタイムの改善に専念できます。

## オチ

Go 1.5のGCは、stop-the-worldの一時停止が安全で安心な言語への移行を妨げる障害ではなくなる未来をもたらします。
それはハードウェアとともにアプリケーションが苦もなくスケールし、ハードウェアがより強力になるにつれてGCが
より優れた、よりスケーラブルなソフトウェアの障害にならない未来です。これから先の10年、そしてそれ以降にとっても、
良い立ち位置だと言えるでしょう。1.5のGCの詳細や、私たちがどのようにレイテンシの問題を解消したかについては、
[Go GC: Latency Problem Solved](https://www.youtube.com/watch?v=aiv1JOfMjm0)のプレゼンテーションや
[スライド](/talks/2015/go-gc.pdf)をご覧ください。

By Richard Hudson

