[インデックス 13428] ファイルの概要
このコミットでは、Goランタイムのメモリ管理に関連する複数のファイルが変更されています。主な変更点は、freemcache()
という新しい関数の追加と、既存の purgecachedstats()
関数の引数変更です。
src/pkg/runtime/malloc.goc
: メモリ割り当てのコアロジックが含まれるファイルで、purgecachedstats
の呼び出し元が更新され、freemcache
関数が追加されています。src/pkg/runtime/malloc.h
: メモリ割り当て関連の関数プロトタイプが定義されているヘッダーファイルで、freemcache
の宣言とpurgecachedstats
の引数変更が反映されています。src/pkg/runtime/mgc0.c
: ガベージコレクション (GC) の統計処理に関連するファイルで、purgecachedstats
の呼び出し元が更新されています。src/pkg/runtime/mheap.c
: グローバルヒープ (MHeap) の管理に関連するファイルで、purgecachedstats
の呼び出し元が更新されています。src/pkg/runtime/runtime.h
: ランタイム全体の共通ヘッダーファイルで、freemcache
の関数プロトタイプが追加されています。
コミット
runtime: add freemcache() function
It will be required for scheduler that maintains
GOMAXPROCS MCache's.
R=golang-dev, r
CC=golang-dev
https://golang.org/cl/6350062
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/ed516df4e43c5e3467bd6a39ffc9277157574788
元コミット内容
commit ed516df4e43c5e3467bd6a39ffc9277157574788
Author: Dmitriy Vyukov <dvyukov@google.com>
Date: Sun Jul 1 13:10:01 2012 +0400
runtime: add freemcache() function
It will be required for scheduler that maintains
GOMAXPROCS MCache's.
R=golang-dev, r
CC=golang-dev
https://golang.org/cl/6350062
---
src/pkg/runtime/malloc.goc | 18 +++++++++++++-----\n src/pkg/runtime/malloc.h | 2 +-\n src/pkg/runtime/mgc0.c | 4 ++--\n src/pkg/runtime/mheap.c | 4 ++--\n src/pkg/runtime/runtime.h | 1 +\n 5 files changed, 19 insertions(+), 10 deletions(-)\n
変更の背景
このコミットの主な目的は、Goランタイムに freemcache()
関数を追加することです。コミットメッセージには「スケジューラが GOMAXPROCS
の MCache
を維持するために必要となる」と明記されています。
Goのランタイムスケジューラは、Goプログラムの並行実行を管理します。GOMAXPROCS
は、同時に実行できるOSスレッドの最大数を制御する環境変数であり、Goランタイムが利用できる論理プロセッサ (P) の数に影響を与えます。各論理プロセッサ (P) には、スレッドローカルなメモリキャッシュである MCache
が関連付けられています。
Goランタイムの進化の過程で、スケジューラは GOMAXPROCS
の値の変更や、プロセッサ (P) の動的な割り当て・解放に応じて、関連する MCache
のライフサイクルを適切に管理する必要が生じました。具体的には、不要になった MCache
を安全かつ効率的に解放するメカニズムが求められていました。
freemcache()
関数は、この MCache
の解放処理をカプセル化するために導入されました。これにより、スケジューラは必要に応じて MCache
をクリーンアップし、メモリリソースを適切に管理できるようになります。また、purgecachedstats()
関数の引数が M*
(OSスレッドを表す構造体) から MCache*
へと変更されたのは、この統計パージ処理が MCache
自体に直接関連するものであり、より汎用的に利用できるようにするためのリファクタリングと考えられます。
前提知識の解説
このコミットを理解するためには、Goランタイムの以下の主要な概念を把握しておく必要があります。
1. Goランタイムの概要
Goランタイムは、Goプログラムの実行を管理するシステムです。これには、ガベージコレクション (GC)、スケジューラ、メモリ管理、プリミティブな同期メカニズムなどが含まれます。Goプログラムは、OSによって直接実行されるのではなく、Goランタイム上で動作します。
2. Goスケジューラ (M, P, Gモデル)
Goスケジューラは、Goの並行処理モデルの中核をなすものです。主に以下の3つの要素で構成されます。
- G (Goroutine): Goにおける軽量な実行単位です。OSスレッドよりもはるかに軽量で、数百万個作成することも可能です。
- M (Machine): OSスレッドを表します。Goランタイムは、Goコードを実行するためにOSスレッドをMとして利用します。Mは、Gを実行したり、システムコールを処理したりします。
- P (Processor): 論理プロセッサを表します。PはMとGの間の仲介役であり、Gを実行するためのコンテキストを提供します。各Pは、実行可能なGのローカルキューを持ち、MはPにアタッチされてGを実行します。
GOMAXPROCS
環境変数は、同時に実行できるPの最大数を決定します。
このモデルにより、Goランタイムは少数のOSスレッド (M) で多数のGoroutine (G) を効率的に多重化し、並行処理を実現します。
3. Goのメモリ管理 (MCache, MHeap, FixAlloc)
Goランタイムは、独自のメモリ管理システムを持っています。
- MHeap (グローバルヒープ): Goプログラムが割り当てるすべてのオブジェクトのメモリが最終的に格納される場所です。MHeapは、大きなメモリチャンク (スパン) を管理し、必要に応じてMCacheに提供します。
- MCache (メモリキャッシュ): 各P (または古いバージョンではM) に関連付けられたスレッドローカルなメモリキャッシュです。Goプログラムが小さなオブジェクトを割り当てる際、まずMCacheからメモリを確保しようとします。これにより、グローバルなMHeapへのアクセスを減らし、ロックの競合を最小限に抑え、割り当てのパフォーマンスを向上させます。MCacheが枯渇すると、MHeapから新しいメモリを取得します。
- FixAlloc: Goランタイム内部のデータ構造 (例えば、MCache自体やMHeapのスパン記述子など) を割り当てるために使用される、固定サイズのオブジェクトアロケータです。これは、特定のサイズのオブジェクトを効率的に割り当てるために設計されています。
4. purgecachedstats
の役割
purgecachedstats
関数は、MCacheに蓄積されたメモリ割り当て統計情報 (例えば、割り当てられたオブジェクトの数やバイト数) を、グローバルなMHeapの統計情報にフラッシュする役割を担います。MCacheはスレッドローカルなため、正確な全体像を得るためには、定期的にその統計情報をグローバルな統計に統合する必要があります。これは、ガベージコレクションの判断やメモリプロファイリングの精度に影響します。
技術的詳細
このコミットにおける技術的な変更点は以下の通りです。
1. freemcache(MCache *c)
関数の導入
- 目的: 不要になった
MCache
オブジェクトを適切に解放し、関連するリソースをクリーンアップするために導入されました。これは、スケジューラがGOMAXPROCS
の変更やプロセッサの動的な管理に伴い、MCache
のライフサイクルを制御する必要があるためです。 - 処理内容:
runtime·MCache_ReleaseAll(c)
:MCache
内に残っているすべてのメモリブロックをグローバルヒープに解放します。これにより、MCacheが保持していたメモリが再利用可能になります。runtime·lock(&runtime·mheap)
: グローバルヒープのロックを取得します。これは、ヒープ統計の更新やFixAlloc
からのメモリ解放が競合しないようにするためです。runtime·purgecachedstats(c)
:MCache
の統計情報をグローバルな統計にフラッシュします。これにより、解放されるMCache
の統計が失われることなく、全体のメモリ使用状況に反映されます。runtime·FixAlloc_Free(&runtime·mheap.cachealloc, c)
:FixAlloc
を使用して割り当てられたMCache
オブジェクト自体を解放します。runtime·mheap.cachealloc
は、MCacheオブジェクトを管理するためのFixAlloc
インスタンスです。runtime·unlock(&runtime·mheap)
: グローバルヒープのロックを解放します。
2. purgecachedstats
関数の引数変更
- 変更前:
void runtime·purgecachedstats(M* m)
- 変更後:
void runtime·purgecachedstats(MCache* c)
- 理由と影響: 以前は
M
(OSスレッド) オブジェクトを引数に取り、そのM
に関連付けられたMCache
を内部で参照していました。この変更により、purgecachedstats
は直接MCache
オブジェクトを引数として受け取るようになりました。これにより、関数がより汎用的になり、MCache
の統計をパージする操作がM
のコンテキストから独立して呼び出せるようになります。これは、関数の責務を明確にし、モジュール性を高める良いリファクタリングです。この変更に伴い、malloc.goc
,mgc0.c
,mheap.c
内のpurgecachedstats
の呼び出し箇所がすべて更新されています。
3. allocmcache
における memclr
の追加
runtime·allocmcache()
関数内で、新しく割り当てられたMCache
オブジェクトc
に対してruntime·memclr((byte*)c, sizeof(*c));
が追加されました。- 目的: これは、新しく確保された
MCache
のメモリ領域をゼロクリアすることを保証します。これにより、以前のメモリ内容が残っていることによる潜在的なバグ (例えば、古いカウンタ値やポインタが残っていること) を防ぎ、MCache
が常にクリーンな状態で初期化されることを保証します。特に、カウンタやフラグなどの数値フィールドがゼロから始まることが期待される場合に重要です。
コアとなるコードの変更箇所
src/pkg/runtime/malloc.goc
における freemcache
の追加
--- a/src/pkg/runtime/malloc.goc
+++ b/src/pkg/runtime/malloc.goc
@@ -246,12 +247,19 @@ runtime·allocmcache(void)
}
void
-runtime·purgecachedstats(M* m)
+runtime·freemcache(MCache *c)
{
-\tMCache *c;\n+\truntime·MCache_ReleaseAll(c);\n+\truntime·lock(&runtime·mheap);\n+\truntime·purgecachedstats(c);\n+\truntime·FixAlloc_Free(&runtime·mheap.cachealloc, c);\n+\truntime·unlock(&runtime·mheap);\n+}\n \n+void\n+runtime·purgecachedstats(MCache *c)
+{\n \t// Protected by either heap or GC lock.\n-\tc = m->mcache;\n \tmstats.heap_alloc += c->local_cachealloc;\n \tc->local_cachealloc = 0;\n \tmstats.heap_objects += c->local_objects;\
src/pkg/runtime/malloc.h
における purgecachedstats
の引数変更と freemcache
の宣言
--- a/src/pkg/runtime/malloc.h
+++ b/src/pkg/runtime/malloc.h
@@ -401,7 +401,7 @@ void runtime·markspan(void *v, uintptr size, uintptr n, bool leftover);\n void runtime·unmarkspan(void *v, uintptr size);\n bool runtime·blockspecial(void*);\n void runtime·setblockspecial(void*, bool);\n-void runtime·purgecachedstats(M*);\n+void runtime·purgecachedstats(MCache*);\n
enum
{
src/pkg/runtime/runtime.h
における freemcache
の宣言
--- a/src/pkg/runtime/runtime.h
+++ b/src/pkg/runtime/runtime.h
@@ -590,6 +590,7 @@ int32 runtime·funcline(Func*, uintptr);\n void* runtime·stackalloc(uint32);\n void runtime·stackfree(void*, uintptr);\n MCache* runtime·allocmcache(void);\n+void runtime·freemcache(MCache*);\n void runtime·mallocinit(void);\n bool runtime·ifaceeq_c(Iface, Iface);\n bool runtime·efaceeq_c(Eface, Eface);\
コアとなるコードの解説
runtime·freemcache(MCache *c)
この関数は、引数として渡された MCache
オブジェクト c
を解放する責任を持ちます。
runtime·MCache_ReleaseAll(c);
:MCache
が保持しているすべてのメモリブロック (スパン) をグローバルヒープに返却します。これにより、これらのメモリは他の割り当てのために再利用可能になります。runtime·lock(&runtime·mheap);
とruntime·unlock(&runtime·mheap);
: グローバルヒープ (runtime·mheap
) へのアクセスを保護するためのロックです。purgecachedstats
の呼び出しとFixAlloc_Free
によるメモリ解放がアトミックに行われることを保証します。runtime·purgecachedstats(c);
: 解放されるMCache
のローカル統計情報をグローバルな統計にフラッシュします。これにより、このMCache
が使用していた期間の正確な統計がシステム全体に反映されます。runtime·FixAlloc_Free(&runtime·mheap.cachealloc, c);
:MCache
オブジェクト自体がFixAlloc
を使って割り当てられているため、そのFixAlloc
インスタンス (runtime·mheap.cachealloc
) を通じてMCache
オブジェクトのメモリを解放します。
runtime·purgecachedstats
の引数変更
runtime·purgecachedstats
の関数シグネチャが M*
から MCache*
に変更されました。
- 変更前は、
M
(OSスレッド) オブジェクトからm->mcache
を介してMCache
を取得していました。 - 変更後は、直接
MCache
オブジェクトを受け取るため、この関数はMCache
の統計をパージするという単一の責務に集中できるようになりました。これにより、コードの可読性と再利用性が向上します。
runtime·allocmcache
における memclr
の追加
runtime·allocmcache
関数内で、新しく割り当てられた MCache
オブジェクト c
のメモリ領域全体が runtime·memclr((byte*)c, sizeof(*c));
によってゼロクリアされます。これは、確保されたメモリが不定な値を含まないことを保証し、特にカウンタやポインタなどのフィールドが初期状態でゼロであることを期待するGoランタイムの内部ロジックにとって重要です。これにより、潜在的なバグや予期せぬ動作を防ぎます。
関連リンク
- Go CL (Code Review) リンク: https://golang.org/cl/6350062
参考にした情報源リンク
- Goの公式ドキュメントやソースコード (Goランタイムの内部構造に関する一般的な知識)
- Goのメモリ管理とスケジューラに関する一般的な技術記事やブログポスト (MCache, MHeap, M-P-Gモデルの概念理解のため)