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

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

このコミットは、Go言語のランタイムパッケージ内のgc_test.goファイルに関連するものです。gc_test.goは、Goランタイムのガベージコレクション(GC)メカニズムの動作と性能をテストするために使用されるファイルです。このファイルには、GCの挙動を検証し、メモリ管理が正しく機能していることを確認するためのテストケースが含まれています。

コミット

commit 244706bd0f6d190559073141c378c874636e4341
Author: Ian Lance Taylor <iant@golang.org>
Date:   Fri Apr 20 11:36:06 2012 -0700

    runtime: disable memory profiler in gc_test
    
    This lets the test pass on PPC64 GNU/Linux, which uses a much
    larger page size and thus uses more memory to hold blocks
    allocated for memory profiling.
    
    R=golang-dev, rsc
    CC=golang-dev
    https://golang.org/cl/6048054

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

https://github.com/golang/go/commit/244706bd0f6d190559073141c378c874636e4341

元コミット内容

runtime: disable memory profiler in gc_test

This lets the test pass on PPC64 GNU/Linux, which uses a much
larger page size and thus uses more memory to hold blocks
allocated for memory profiling.

R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/6048054

変更の背景

この変更は、gc_testがPPC64 GNU/Linux環境で失敗する問題を解決するために導入されました。PPC64 GNU/Linuxは、他の一般的なアーキテクチャ(x86-64など)と比較して、より大きなメモリページサイズを使用する傾向があります。メモリプロファイラが有効になっている場合、プロファイリングのために割り当てられるブロックが、この大きなページサイズのために予想以上に多くのメモリを消費していました。その結果、gc_testがメモリ不足や、テストの期待値を超えるメモリ使用量となり、テストが失敗していました。この問題を回避し、PPC64 GNU/Linux上でもテストが正常に完了するように、gc_test実行中にメモリプロファイラを無効にする必要がありました。

前提知識の解説

  • メモリプロファイラ (Memory Profiler): プログラムのメモリ使用量を追跡し、どの部分がどれくらいのメモリを割り当てているか、どこでメモリリークが発生しているかなどを分析するためのツールです。Go言語のランタイムには、このメモリプロファイリング機能が組み込まれており、runtime.MemProfileRateという変数でその動作を制御できます。
  • gc_test: Goランタイムのガベージコレクション(GC)の動作を検証するためのテストスイートです。GCは、プログラムが不要になったメモリを自動的に解放するプロセスであり、その効率性と正確性はGoアプリケーションのパフォーマンスと安定性に直結します。gc_testは、GCが正しくメモリを回収し、システム全体のメモリ使用量(Sys)が適切に管理されていることを確認します。
  • runtime.MemProfileRate: Go言語のruntimeパッケージで提供される変数で、メモリプロファイリングのサンプリングレートを制御します。この値が0の場合、メモリプロファイリングは無効になります。正の値の場合、その値がサンプリングレートとして使用され、例えばMemProfileRate = 1は1バイトごとにサンプリングすることを意味します(ただし、実際にはより大きなブロックでサンプリングされます)。
  • ページサイズ (Page Size): オペレーティングシステムがメモリを管理する最小単位です。仮想メモリシステムでは、物理メモリは固定サイズの「ページ」に分割され、プロセスはこれらのページを割り当てて使用します。ページサイズが大きいほど、メモリ管理のオーバーヘッドは減少する可能性がありますが、小さな割り当てでも大きなページ全体が消費されるため、メモリの断片化や無駄が生じる可能性もあります。
  • PPC64 GNU/Linux: IBMのPowerPC 64ビットアーキテクチャ上で動作するGNU/Linuxオペレーティングシステムです。PPC64アーキテクチャは、x86-64とは異なるメモリ管理特性を持つことがあり、特にデフォルトのメモリページサイズが大きくなる傾向があります。Web検索の結果によると、PPC64 GNU/Linuxでは通常64KBのページサイズが使用されることが多いようです。

技術的詳細

Goのメモリプロファイラは、プログラムがメモリを割り当てる際に、その割り当てに関する情報を記録します。この情報は、プロファイリングデータとして内部的に保持されます。このプロファイリングデータ自体もメモリを消費します。

PPC64 GNU/Linuxのようなシステムでページサイズが非常に大きい(例えば64KB)場合、メモリプロファイラが割り当てる小さなブロックであっても、OSからはページ単位でメモリが割り当てられます。つまり、たとえ数バイトのプロファイリングデータのためにメモリを要求しても、OSは最小単位である64KBのページを割り当てることになります。

gc_testは、ガベージコレクションの効率性をテストするために、大量のオブジェクトを生成・破棄するような処理を繰り返します。この過程でメモリプロファイラが有効になっていると、プロファイリングデータのために大量の小さなメモリ割り当てが発生し、それが大きなページサイズと組み合わされることで、実際に必要なメモリ量よりもはるかに多くの物理メモリがOSから割り当てられてしまいます。

結果として、gc_testが想定するメモリ使用量の範囲を超過し、テストが失敗する原因となっていました。この問題を解決するために、gc_testの実行中に一時的にメモリプロファイラを無効にすることで、プロファイリングデータのための余分なメモリ割り当てをなくし、テストが正常に完了するようにしました。

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

--- a/src/pkg/runtime/gc_test.go
+++ b/src/pkg/runtime/gc_test.go
@@ -15,6 +15,8 @@ func TestGcSys(t *testing.T) {
 	runtime.ReadMemStats(memstats)
 	sys := memstats.Sys
 
+	runtime.MemProfileRate = 0 // disable profiler
+
 	itercount := 1000000
 	if testing.Short() {
 		itercount = 100000

コアとなるコードの解説

追加された行は以下の通りです。

	runtime.MemProfileRate = 0 // disable profiler

この行は、TestGcSys関数の冒頭に追加されています。runtime.MemProfileRate0を代入することで、Goランタイムのメモリプロファイリング機能を無効にしています。これにより、TestGcSysが実行されている間は、メモリ割り当てに関するプロファイリングデータが収集されなくなり、プロファイリングデータのために余分なメモリが消費されることがなくなります。

この変更は、特定のテスト(TestGcSys)の実行時のみメモリプロファイラを無効にするため、Goランタイム全体のメモリプロファイリング機能には影響を与えません。これは、テストの実行環境に起因する特定の問題を解決するための、局所的かつ効果的な修正です。

関連リンク

参考にした情報源リンク