2025年10月29日にリリースされたGo 1.25において、Go言語のランタイムに革新的なアップデートが導入されました。

その中心となるのが、試験的機能として実装された新しいガベージコレクタ(GC)アルゴリズム、通称「Green Tea」です。

この新機能は、Googleの膨大なプロダクション環境での検証を経て公開されており、多くのワークロードでGCにかかる時間を約10%削減し、特定のケースでは最大40%ものパフォーマンス向上を実現しています。

現代のハードウェア特性を最大限に引き出すこの新GCが、なぜこれほどまでの成果を上げているのか、その仕組みと背景を詳しく解説します。

Go言語におけるGCの役割と従来の仕組み

Go言語の大きな特徴の一つは、プログラマが明示的にメモリを解放する必要がない「メモリ安全な言語」であることです。

これを支えているのがガベージコレクタです。

オブジェクトとポインタの管理

Goのランタイムにおいて、GCが主に対象とするのは「ヒープ」と呼ばれるメモリ領域に割り当てられたオブジェクトです。

コンパイラがスタックに割り当てられないと判断したデータはヒープに置かれます。

例えば、以下のコードのようにスライスをグローバル変数として定義する場合、その実体はヒープに確保されます。

go
// グローバル変数としてポインタのスライスを定義
var x = make([]*int, 10)

func init() {
    for i := 0; i < 10; i++ {
        val := i
        // 各要素にヒープオブジェクトへのポインタを格納
        x[i] = &val
    }
}

プログラムはポインタ(メモリ上の場所を示す数値)を通じてこれらのオブジェクトを参照します。

GCは、プログラムがどのポインタを通じてどのオブジェクトにアクセス可能かを追跡し、どこからも参照されなくなった「到達不能」なメモリを自動的に回収して再利用します。

伝統的なマーク・アンド・スイープ・アルゴリズム

これまでGoが採用してきたのは、「トレース型ガベージコレクション」の一種である「マーク・アンド・スイープ」というアルゴリズムです。

これは非常にシンプルな2段階のプロセスで構成されています。

  1. マークフェーズ:グローバル変数やローカル変数といった「ルート」からポインタを辿り、見つかったすべてのオブジェクトに「訪問済み」の印を付けます。
  2. スイープフェーズ:印が付いていないオブジェクトを「未使用」と判断し、メモリを解放してアロケータ(メモリ割り当て器)に返却します。

このプロセスはプログラムの実行と並行して行われますが、オブジェクトの数が増え、グラフ構造が複雑になるほど、ポインタを辿るコストが膨大になるという課題を抱えていました。

現代のCPUを悩ませる「マイクロアーキテクチャの悲劇」

従来のマーク・アンド・スイープ・アルゴリズムは、論理的には完璧でしたが、現代のCPUハードウェアとの相性という点では大きな非効率性を抱えていました。

Go開発チームはこれを「マイクロアーキテクチャ上の災害(disaster)」と表現しています。

メモリレイテンシとキャッシュミス

現代のCPUは、メモリへのアクセス速度を稼ぐために多層のキャッシュ(L1, L2, L3)を備えています。

メインメモリ(RAM)へのアクセスは、キャッシュへのアクセスに比べて最大100倍近く遅い場合があります。

従来のGCアルゴリズムは、ポインタを一つずつ辿ってオブジェクトをスキャンします。

このとき、メモリ上であちこちに散らばったオブジェクトをランダムに読みに行くことになり、頻繁に「キャッシュミス」が発生します。

CPUから見れば、次にどこのメモリを読むか予測できず、データが届くまで計算を中断して待機しなければならない時間が頻発している状態です。

ハードウェアトレンドとの乖離

さらに、近年のハードウェアの進化がこの問題を深刻化させています。

  • NUMA (Non-Uniform Memory Access):CPUコアごとに近いメモリと遠いメモリが存在し、アクセス速度が不均一になっています。
  • メモリ帯域の相対的な低下:CPUのコア数が増える一方で、一つのコアあたりのメモリ転送能力(帯域)は相対的に減少傾向にあります。
  • 共有キューのボトルネック:多数のコアで並列にGCを実行しようとすると、次にスキャンすべきオブジェクトを管理する「共有ワークリスト」へのアクセスが競合し、オーバーヘッドが生じます。

これらの要因により、プログラムの実行時間の20%以上がGCに費やされるケースも珍しくありませんでした。

新アルゴリズム「Green Tea」の核心

2024年に開発が始まり、2025年に結実したGreen Tea GCの考え方は非常にシンプルです。

それは、「オブジェクト単位ではなく、ページ単位で作業する」というパラダイムシフトです。

ページベースのスキャンへの転換

Goのメモリ管理では、8KiB(8192バイト)の固定サイズのブロックである「ページ」という単位でメモリを整理しています。

Green Teaは、ワークリストで個々のオブジェクトを管理する代わりに、「スキャンが必要なオブジェクトを含むページ」を管理します。

  1. ポインタを見つけたとき、その先にあるオブジェクトを直接ワークリストに入れるのではなく、そのオブジェクトが属するページ全体をキューに入れます。
  2. そのページがキューから取り出されるまで、同じページ内の他のオブジェクトに対するマーク処理を保留(蓄積)します。
  3. ページを取り出す際、そのページ内に存在する「マーク済みだが未スキャン」のオブジェクトを、メモリ上のアドレス順にまとめてスキャンします。

この「怠惰な蓄積」により、メモリをジャンプしながら読み取る回数が劇的に減り、連続した領域を効率よく読み取れるようになります。

これが、CPUキャッシュのヒット率向上に直結します。

2つのメタデータビットによる管理

Green Teaを実現するために、各オブジェクトに対して2種類のメタデータビットが用意されました。

  • seenビット:ポインタによって到達可能であることが確認された(マークされた)ことを示す。
  • scannedビット:そのオブジェクト内のポインタがすでにスキャンされたことを示す。

これら2つのビットの差分をチェックすることで、ページ内のどのオブジェクトが新たにスキャン待ちになっているかを瞬時に判断できます。

AVX-512によるハードウェア加速

Green Teaの真価は、最新CPUのベクトル演算命令(AVX-512)を活用した高速化にあります。

これまでのオブジェクト単位のスキャンでは、データのサイズがバラバラだったためベクトル演算の導入が困難でした。

しかし、ページ単位で処理をまとめたことで、規則的なデータ処理が可能になりました。

ビットベクトルの「スイスアーミーナイフ」

IntelのIce LakeやAMDのZen 4以降のCPUでサポートされているVGF2P8AFFINEQB命令などが活用されています。

  1. ページのメタデータ(seenscannedビット)を512ビット幅のベクトルレジスタに読み込みます。
  2. レジスタ内でビット演算を行い、「スキャンが必要なオブジェクト」を特定します。
  3. 特定のビット行列演算を用いることで、どの単語(ワード)がポインタであるかを一気に展開し、特定します。

この高度な最適化により、ページ全体のメタデータ処理をわずか数サイクルで完了させることができます。

Goのランタイムチームは、この処理のために専用のアセンブリコードを生成するツールまで開発し、極限のパフォーマンスを追求しました。

Green Teaの導入効果と今後の展望

Green Tea GCは、すでにGo 1.25において試験的な機能として提供されており、ビルド時にフラグを指定することで利用可能です。

パフォーマンス指標

ベンチマークおよびGoogle内での実運用のデータによれば、以下のような結果が得られています。

指標改善率(平均的)最大改善率
GC CPUコストの削減約 10%約 40%
全体的なCPU使用率の削減1% 〜 4%ワークロードによる

ただし、すべてのケースで速くなるわけではありません。

ページ内のオブジェクト密度が極端に低く、一つのページにつき一つのオブジェクトしかスキャン対象がないような特殊なデータ構造では、従来の方式と変わらないか、あるいはメタデータ管理の分だけわずかに遅くなる可能性もあります。

しかし、Goチームはこうした回帰(退行)を最小限に抑えるための特殊なケース処理も実装しています。

利用方法と将来のロードマップ

Go 1.25を使用している環境では、環境変数GOEXPERIMENTを設定してビルドすることで、この機能を有効にできます。

Shell
# Green Tea GCを有効にしてビルドする
GOEXPERIMENT=greenteagc go build main.go

Go開発チームの計画では、2026年リリースのGo 1.26においてGreen TeaをデフォルトのGCにする予定です。

Go 1.26ではさらにベクトル加速の最適化が追加され、x86以外のアーキテクチャ(ARM64など)への展開も期待されています。

まとめ

Go 1.25で登場した「Green Tea」は、単なるアルゴリズムの修正にとどまらず、ソフトウェアが現代の複雑なハードウェア(CPUマイクロアーキテクチャ)といかに協調すべきかを示す象徴的なアップデートです。

「オブジェクトを追う」という抽象的なグラフ探索から、「物理的なメモリページを効率よく読み抜く」というハードウェア寄りのアプローチへ転換したことで、GCはさらなる高みへ到達しました。

特に大規模なヒープを抱えるマイクロサービスや、高トラフィックなAPIサーバーにおいて、その恩恵は計り知れません。

2026年のGo 1.26における標準採用を前に、パフォーマンスに敏感なエンジニアは今すぐGOEXPERIMENT=greenteagcを試し、その圧倒的な効率性を体感してみるべきでしょう。

Go言語は、誕生から十数年を経てもなお、そのランタイムを劇的に進化させ続けています。