Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 10775] ファイルの概要

このコミットは、Go言語のランタイムにおけるガベージコレクション(GC)のテストファイル src/pkg/runtime/gc_test.go に変更を加えています。具体的には、GCが使用する「余分なバイト数(extra bytes)」のチェック閾値を引き上げています。

コミット

runtime: bump gc 'extra bytes' check

(needed for non-zero GOMAXPROCS)

R=iant, rsc
CC=go.peter.90, golang-dev
https://golang.org/cl/5486059

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/1e63a4e4242389fdd1c5f90efa8c221c3bd2701b

元コミット内容

Goランタイムのガベージコレクションにおける「余分なバイト数」のチェック閾値を引き上げる変更です。この変更は、GOMAXPROCS がゼロでない(つまり、複数のCPUコアを使用する)場合に必要とされました。

変更の背景

このコミットが行われた2011年頃のGo言語は、まだ比較的新しい言語であり、ランタイムやガベージコレクタの最適化が活発に行われていました。特に、マルチコアプロセッサを効率的に利用するための GOMAXPROCS の導入と、それに伴うGCの挙動の調整は重要な課題でした。

GOMAXPROCS は、Goランタイムが同時に実行できるOSスレッドの最大数を制御する環境変数です。デフォルトではCPUコア数に設定されますが、当時はデフォルトが1であった時期もありました。GOMAXPROCS が1より大きい値に設定されると、Goランタイムは複数のOSスレッドを使用してGoルーチンを並行して実行します。これにより、プログラムは複数のCPUコアを最大限に活用できるようになります。

しかし、複数のOSスレッドが同時に動作する環境では、ガベージコレクタの動作もより複雑になります。GCは、プログラムが使用しなくなったメモリを解放する役割を担いますが、その過程で一時的に追加のメモリを使用することがあります。これは、GCがオブジェクトを移動したり、マークしたり、スイープしたりする際に発生するオーバーヘッドです。

gc_test.go 内の TestGcSys テストは、GCがシステムから取得するメモリ量(runtime.MemStats.Sys)を監視し、その増加が許容範囲内であることを確認するためのものです。コミットメッセージにある「(needed for non-zero GOMAXPROCS)」という記述は、GOMAXPROCS が1より大きい場合に、GCが使用する「余分なバイト数」が増加し、既存のテストの閾値 2<<20 (2MB) を超えてしまうようになったことを示唆しています。これは、並行GCの動作や、複数のプロセッサが同時にメモリを操作することによる競合、キャッシュの無効化などが原因で、GCのオーバーヘッドが増大したためと考えられます。

この変更は、GOMAXPROCS > 0 の環境下でも TestGcSys テストが正しくパスするように、GCの「余分なバイト数」の許容閾値を 2MB から 4MB に引き上げることで、テストの誤検出を防ぎ、ランタイムの安定性を確保することを目的としています。

前提知識の解説

Goランタイム (Go Runtime)

Goランタイムは、Goプログラムの実行を管理するシステムです。これには、ガベージコレクタ、スケジューラ(GoルーチンをOSスレッドにマッピングする)、メモリ管理、プリミティブな同期メカニズムなどが含まれます。Goプログラムは、OSによって直接実行されるのではなく、このランタイム上で動作します。

ガベージコレクション (Garbage Collection, GC)

ガベージコレクションは、プログラムが動的に割り当てたメモリのうち、もはや到達不可能(参照されていない)になったオブジェクトを自動的に解放するプロセスです。GoのGCは、並行(concurrent)かつ非同期(asynchronous)に動作するように設計されており、プログラムの実行を長時間停止させることなくメモリを回収します。これにより、レイテンシ(遅延)を最小限に抑え、高いスループットを維持します。

runtime.MemStats

runtime.MemStats は、Goプログラムのメモリ使用状況に関する統計情報を提供する構造体です。この構造体には、ヒープの使用量、GCの統計、システムから取得したメモリ量など、様々な情報が含まれています。

  • MemStats.Sys: GoランタイムがOSから取得した総メモリ量(バイト単位)を示します。これには、ヒープ、スタック、GCメタデータなど、ランタイムが使用するすべてのメモリが含まれます。GCが動作すると、一時的にこの値が増加することがあります。

GOMAXPROCS

GOMAXPROCS は、Goランタイムが同時に実行できるOSスレッドの最大数を制御する環境変数です。Goルーチンは、このOSスレッド上で実行されます。

  • GOMAXPROCS=1: Goランタイムは1つのOSスレッドのみを使用し、Goルーチンは協調的マルチタスク(cooperative multitasking)で実行されます。この場合、Goルーチンは明示的にスケジューラに制御を譲るか、I/O操作などでブロックされるまで実行を続けます。
  • GOMAXPROCS > 1: Goランタイムは複数のOSスレッドを使用し、Goルーチンは並行して実行されます。これにより、マルチコアプロセッサの恩恵を最大限に受けることができます。しかし、複数のスレッドが同時にメモリを操作するため、GCの複雑性が増し、オーバーヘッドが増加する可能性があります。

2<<204<<20

これはビットシフト演算子を使用した数値表現です。

  • 2<<202 * (2^20) を意味します。2^20 は1メガバイト(1MB)なので、2<<202MB に相当します。
  • 4<<204 * (2^20) を意味します。これは 4MB に相当します。

このテストでは、GCが一時的に使用するメモリの許容上限を 2MB から 4MB に引き上げています。

技術的詳細

TestGcSys テストは、Goランタイムのガベージコレクタが、その動作中にシステムから過剰なメモリを要求しないことを検証するために存在します。テストのロジックは以下の通りです。

  1. テスト開始時の runtime.MemStats.Sys の値を記録します。
  2. GCを強制的に実行します(runtime.GC())。
  3. GC実行後の runtime.MemStats.Sys の値を記録し、開始時との差分を計算します。この差分が「GCが使用した余分なバイト数」と見なされます。
  4. この「余分なバイト数」が事前に定義された閾値を超えていないかを確認します。超えている場合、テストは失敗します。

このコミット以前は、閾値が 2<<20 (2MB) に設定されていました。しかし、コミットメッセージにあるように「non-zero GOMAXPROCS」(つまり、複数のCPUコアを使用する設定)の場合に、この閾値を超えてしまう問題が発生しました。

この問題の根本原因は、GOMAXPROCS が1より大きい場合に、Goの並行GCがより多くのメモリを一時的に必要とするようになったためと考えられます。考えられる理由はいくつかあります。

  • 並行GCのオーバーヘッド: 複数のプロセッサが同時にGC作業を行うことで、GCの内部データ構造(例えば、マークビットマップやスキャンキュー)がより大きくなる可能性があります。また、複数のプロセッサ間でキャッシュの一貫性を維持するためのオーバーヘッドも発生します。
  • アロケーションの増加: 並行GCは、プログラムの実行と並行して動作するため、GCがメモリを回収する前に、プログラムが新しいオブジェクトを割り当て続ける可能性があります。これにより、一時的にメモリ使用量が増加することがあります。
  • スケジューリングの複雑性: 複数のOSスレッドとGoルーチンが複雑に絡み合うことで、GCが効率的にメモリを回収するタイミングが難しくなり、一時的なメモリフットプリントが増大する可能性があります。

このコミットは、これらの要因によってGCの「余分なバイト数」が 2MB を超えるようになったことを認識し、テストの閾値を 4MB に引き上げることで、テストが実際のランタイムの挙動に即したものとなるように調整しました。これは、GCの効率が低下したことを意味するのではなく、マルチコア環境でのGCの動作特性を考慮した、より現実的な閾値設定と言えます。

コアとなるコードの変更箇所

--- a/src/pkg/runtime/gc_test.go
+++ b/src/pkg/runtime/gc_test.go
@@ -22,7 +22,7 @@ func TestGcSys(t *testing.T) {
 		sys = runtime.MemStats.Sys - sys
 	}\n \tt.Logf(\"used %d extra bytes\", sys)\n-\tif sys > 2<<20 {\n+\tif sys > 4<<20 {\n \t\tt.Fatalf(\"using too much memory: %d bytes\", sys)\n \t}\n }\n```

## コアとなるコードの解説

変更は `src/pkg/runtime/gc_test.go` ファイルの `TestGcSys` 関数内の一行です。

元のコード:
```go
if sys > 2<<20 {

変更後のコード:

if sys > 4<<20 {

この変更は、TestGcSys テストにおけるGCの「余分なバイト数」の許容上限を 2MB から 4MB に引き上げています。

  • sys 変数には、runtime.GC() を呼び出す前後の runtime.MemStats.Sys の差分、つまりGCが一時的に使用した追加のシステムメモリ量が格納されます。
  • 元の 2<<202 * 2^20 = 2 * 1048576 = 2097152 バイト、すなわち 2MB です。
  • 変更後の 4<<204 * 2^20 = 4 * 1048576 = 4194304 バイト、すなわち 4MB です。

この変更により、GOMAXPROCS がゼロでない環境でGCが 2MB を超えるが 4MB 以内の追加メモリを使用した場合でも、TestGcSys テストが失敗しなくなります。これは、マルチコア環境でのGCの動作特性を考慮し、テストの誤検出を避けるための調整であり、GCの効率が著しく低下したことを意味するものではありません。むしろ、Goランタイムがより多くのプロセッサを効率的に利用できるようにするための、現実的なチューニングの一環と見ることができます。

関連リンク

参考にした情報源リンク

  • Goのガベージコレクションに関する一般的な情報源 (例: Go公式ドキュメント、GoブログのGCに関する記事)
  • GOMAXPROCS に関する情報源 (例: Go公式ドキュメント、Goブログの記事)
  • runtime.MemStats のドキュメント
  • Go言語の歴史と進化に関する情報源 (特に2011年頃のランタイム開発状況)
  • https://github.com/golang/go/commit/1e63a4e4242389fdd1c5f90efa8c221c3bd2701b (GitHubコミットページ)
  • https://golang.org/cl/5486059 (Go Code Review - CL 5486059)# [インデックス 10775] ファイルの概要

このコミットは、Go言語のランタイムにおけるガベージコレクション(GC)のテストファイル src/pkg/runtime/gc_test.go に変更を加えています。具体的には、GCが使用する「余分なバイト数(extra bytes)」のチェック閾値を引き上げています。

コミット

runtime: bump gc 'extra bytes' check

(needed for non-zero GOMAXPROCS)

R=iant, rsc
CC=go.peter.90, golang-dev
https://golang.org/cl/5486059

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/1e63a4e4242389fdd1c5f90efa8c221c3bd2701b

元コミット内容

Goランタイムのガベージコレクションにおける「余分なバイト数」のチェック閾値を引き上げる変更です。この変更は、GOMAXPROCS がゼロでない(つまり、複数のCPUコアを使用する)場合に必要とされました。

変更の背景

このコミットが行われた2011年頃のGo言語は、まだ比較的新しい言語であり、ランタイムやガベージコレクタの最適化が活発に行われていました。特に、マルチコアプロセッサを効率的に利用するための GOMAXPROCS の導入と、それに伴うGCの挙動の調整は重要な課題でした。

GOMAXPROCS は、Goランタイムが同時に実行できるOSスレッドの最大数を制御する環境変数です。デフォルトではCPUコア数に設定されますが、当時はデフォルトが1であった時期もありました。GOMAXPROCS が1より大きい値に設定されると、Goランタイムは複数のOSスレッドを使用してGoルーチンを並行して実行します。これにより、プログラムは複数のCPUコアを最大限に活用できるようになります。

しかし、複数のOSスレッドが同時に動作する環境では、ガベージコレクタの動作もより複雑になります。GCは、プログラムが使用しなくなったメモリを解放する役割を担いますが、その過程で一時的に追加のメモリを使用することがあります。これは、GCがオブジェクトを移動したり、マークしたり、スイープしたりする際に発生するオーバーヘッドです。

gc_test.go 内の TestGcSys テストは、GCがシステムから取得するメモリ量(runtime.MemStats.Sys)を監視し、その増加が許容範囲内であることを確認するためのものです。コミットメッセージにある「(needed for non-zero GOMAXPROCS)」という記述は、GOMAXPROCS が1より大きい場合に、GCが使用する「余分なバイト数」が増加し、既存のテストの閾値 2<<20 (2MB) を超えてしまうようになったことを示唆しています。これは、並行GCの動作や、複数のプロセッサが同時にメモリを操作することによる競合、キャッシュの無効化などが原因で、GCのオーバーヘッドが増大したためと考えられます。

この変更は、GOMAXPROCS > 0 の環境下でも TestGcSys テストが正しくパスするように、GCの「余分なバイト数」の許容閾値を 2MB から 4MB に引き上げることで、テストの誤検出を防ぎ、ランタイムの安定性を確保することを目的としています。

前提知識の解説

Goランタイム (Go Runtime)

Goランタイムは、Goプログラムの実行を管理するシステムです。これには、ガベージコレクタ、スケジューラ(GoルーチンをOSスレッドにマッピングする)、メモリ管理、プリミティブな同期メカニズムなどが含まれます。Goプログラムは、OSによって直接実行されるのではなく、このランタイム上で動作します。

ガベージコレクション (Garbage Collection, GC)

ガベージコレクションは、プログラムが動的に割り当てたメモリのうち、もはや到達不可能(参照されていない)になったオブジェクトを自動的に解放するプロセスです。GoのGCは、並行(concurrent)かつ非同期(asynchronous)に動作するように設計されており、プログラムの実行を長時間停止させることなくメモリを回収します。これにより、レイテンシ(遅延)を最小限に抑え、高いスループットを維持します。

runtime.MemStats

runtime.MemStats は、Goプログラムのメモリ使用状況に関する統計情報を提供する構造体です。この構造体には、ヒープの使用量、GCの統計、システムから取得したメモリ量など、様々な情報が含まれています。

  • MemStats.Sys: GoランタイムがOSから取得した総メモリ量(バイト単位)を示します。これには、ヒープ、スタック、GCメタデータなど、ランタイムが使用するすべてのメモリが含まれます。GCが動作すると、一時的にこの値が増加することがあります。

GOMAXPROCS

GOMAXPROCS は、Goランタイムが同時に実行できるOSスレッドの最大数を制御する環境変数です。Goルーチンは、このOSスレッド上で実行されます。

  • GOMAXPROCS=1: Goランタイムは1つのOSスレッドのみを使用し、Goルーチンは協調的マルチタスク(cooperative multitasking)で実行されます。この場合、Goルーチンは明示的にスケジューラに制御を譲るか、I/O操作などでブロックされるまで実行を続けます。
  • GOMAXPROCS > 1: Goランタイムは複数のOSスレッドを使用し、Goルーチンは並行して実行されます。これにより、マルチコアプロセッサの恩恵を最大限に受けることができます。しかし、複数のスレッドが同時にメモリを操作するため、GCの複雑性が増し、オーバーヘッドが増加する可能性があります。

2<<204<<20

これはビットシフト演算子を使用した数値表現です。

  • 2<<202 * (2^20) を意味します。2^20 は1メガバイト(1MB)なので、2<<202MB に相当します。
  • 4<<204 * (2^20) を意味します。これは 4MB に相当します。

このテストでは、GCが一時的に使用するメモリの許容上限を 2MB から 4MB に引き上げています。

技術的詳細

TestGcSys テストは、Goランタイムのガベージコレクタが、その動作中にシステムから過剰なメモリを要求しないことを検証するために存在します。テストのロジックは以下の通りです。

  1. テスト開始時の runtime.MemStats.Sys の値を記録します。
  2. GCを強制的に実行します(runtime.GC())。
  3. GC実行後の runtime.MemStats.Sys の値を記録し、開始時との差分を計算します。この差分が「GCが使用した余分なバイト数」と見なされます。
  4. この「余分なバイト数」が事前に定義された閾値を超えていないかを確認します。超えている場合、テストは失敗します。

このコミット以前は、閾値が 2<<20 (2MB) に設定されていました。しかし、コミットメッセージにあるように「non-zero GOMAXPROCS」(つまり、複数のCPUコアを使用する設定)の場合に、この閾値を超えてしまう問題が発生しました。

この問題の根本原因は、GOMAXPROCS が1より大きい場合に、Goの並行GCがより多くのメモリを一時的に必要とするようになったためと考えられます。考えられる理由はいくつかあります。

  • 並行GCのオーバーヘッド: 複数のプロセッサが同時にGC作業を行うことで、GCの内部データ構造(例えば、マークビットマップやスキャンキュー)がより大きくなる可能性があります。また、複数のプロセッサ間でキャッシュの一貫性を維持するためのオーバーヘッドも発生します。
  • アロケーションの増加: 並行GCは、プログラムの実行と並行して動作するため、GCがメモリを回収する前に、プログラムが新しいオブジェクトを割り当て続ける可能性があります。これにより、一時的にメモリ使用量が増加することがあります。
  • スケジューリングの複雑性: 複数のOSスレッドとGoルーチンが複雑に絡み合うことで、GCが効率的にメモリを回収するタイミングが難しくなり、一時的なメモリフットプリントが増大する可能性があります。

このコミットは、これらの要因によってGCの「余分なバイト数」が 2MB を超えるようになったことを認識し、テストの閾値を 4MB に引き上げることで、テストが実際のランタイムの挙動に即したものとなるように調整しました。これは、GCの効率が低下したことを意味するのではなく、マルチコア環境でのGCの動作特性を考慮した、より現実的な閾値設定と言えます。

コアとなるコードの変更箇所

--- a/src/pkg/runtime/gc_test.go
+++ b/src/pkg/runtime/gc_test.go
@@ -22,7 +22,7 @@ func TestGcSys(t *testing.T) {
 		sys = runtime.MemStats.Sys - sys
 	}\n \tt.Logf(\"used %d extra bytes\", sys)\n-\tif sys > 2<<20 {\n+\tif sys > 4<<20 {\n \t\tt.Fatalf(\"using too much memory: %d bytes\", sys)\n \t}\n }\n```

## コアとなるコードの解説

変更は `src/pkg/runtime/gc_test.go` ファイルの `TestGcSys` 関数内の一行です。

元のコード:
```go
if sys > 2<<20 {

変更後のコード:

if sys > 4<<20 {

この変更は、TestGcSys テストにおけるGCの「余分なバイト数」の許容上限を 2MB から 4MB に引き上げています。

  • sys 変数には、runtime.GC() を呼び出す前後の runtime.MemStats.Sys の差分、つまりGCが一時的に使用した追加のシステムメモリ量が格納されます。
  • 元の 2<<202 * 2^20 = 2 * 1048576 = 2097152 バイト、すなわち 2MB です。
  • 変更後の 4<<204 * 2^20 = 4 * 1048576 = 4194304 バイト、すなわち 4MB です。

この変更により、GOMAXPROCS がゼロでない環境でGCが 2MB を超えるが 4MB 以内の追加メモリを使用した場合でも、TestGcSys テストが失敗しなくなります。これは、マルチコア環境でのGCの動作特性を考慮し、テストの誤検出を避けるための調整であり、GCの効率が著しく低下したことを意味するものではありません。むしろ、Goランタイムがより多くのプロセッサを効率的に利用できるようにするための、現実的なチューニングの一環と見ることができます。

関連リンク

参考にした情報源リンク

  • Goのガベージコレクションに関する一般的な情報源 (例: Go公式ドキュメント、GoブログのGCに関する記事)
  • GOMAXPROCS に関する情報源 (例: Go公式ドキュメント、Goブログの記事)
  • runtime.MemStats のドキュメント
  • Go言語の歴史と進化に関する情報源 (特に2011年頃のランタイム開発状況)
  • https://github.com/golang/go/commit/1e63a4e4242389fdd1c5f90efa8c221c3bd2701b (GitHubコミットページ)
  • https://golang.org/cl/5486059 (Go Code Review - CL 5486059)