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

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

このコミットは、Goランタイムにおける未使用の moreframesize_minalloc フィールドを削除するものです。このフィールドは、ガベージコレクション(GC)が g0 ゴルーチン(システムゴルーチン)上で実行されていない場合に、GCのために大きなスタックセグメントを要求するために使用されていました。しかし、GCが常に g0 上で実行されるようになったため、このフィールドは不要になりました。

コミット

commit 5caf762457420bf6df0298a8d363ab60216f03bc
Author: Dmitriy Vyukov <dvyukov@google.com>
Date:   Sat Jun 15 16:02:39 2013 +0400

    runtime: remove unused moreframesize_minalloc field
    It was used to request large stack segment for GC
    when it was running not on g0.
    Now GC is running on g0 with large stack,
    and it is not needed anymore.
    
    R=golang-dev, dave
    CC=golang-dev
    https://golang.org/cl/10242045

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

https://github.com/golang/go/commit/5caf762457420bf6df0298a8d363ab60216f03bc

元コミット内容

runtime: remove unused moreframesize_minalloc field
It was used to request large stack segment for GC
when it was running not on g0.
Now GC is running on g0 with large stack,
and it is not needed anymore.

変更の背景

この変更の背景には、Goランタイムのガベージコレクション(GC)の実行モデルの進化があります。以前のGoランタイムでは、GCは必ずしも g0 ゴルーチン(ランタイム内部の処理を行うための特別なゴルーチンで、非常に大きなスタックを持つ)上で実行されるわけではありませんでした。GCが通常のユーザーゴルーチン(g ゴルーチン)のコンテキストで実行される場合、GC処理に必要なスタック領域が不足する可能性がありました。

moreframesize_minalloc フィールドは、このような状況でGCがより大きなスタックセグメントを確保できるようにするためのメカニズムとして導入されました。具体的には、GCがスタックを拡張する必要がある場合に、このフィールドに最小限必要なフレームサイズが設定され、newstack 関数(スタックの拡張を処理する関数)がそのサイズを考慮してスタックを割り当てるように動作していました。

しかし、Goランタイムの設計が進化し、GCが常に g0 ゴルーチン上で実行されるように変更されました。g0 ゴルーチンは最初から十分な大きさのスタックを持っており、GC処理に必要なスタック領域を常に確保できるため、GCがスタック不足に陥る心配がなくなりました。この変更により、moreframesize_minalloc フィールドは完全にその役割を終え、未使用となりました。そのため、コードベースのクリーンアップと複雑性の軽減のために削除されることになりました。

前提知識の解説

このコミットを理解するためには、以下のGoランタイムの概念を理解しておく必要があります。

  1. ゴルーチン (Goroutine): Go言語における軽量な実行スレッドです。OSのスレッドよりもはるかに軽量で、数百万のゴルーチンを同時に実行できます。Goランタイムがゴルーチンのスケジューリング、スタック管理、同期などを担当します。

  2. スタック (Stack): 各ゴルーチンは独自のスタックを持っています。スタックは関数呼び出しの際にローカル変数や引数、リターンアドレスなどを格納するために使用されるメモリ領域です。Goのスタックは動的に伸縮可能であり、必要に応じて自動的に拡張(または縮小)されます。

  3. g0 ゴルーチン (System Goroutine): Goランタイム内部の重要な処理(スケジューリング、ガベージコレクション、システムコールなど)を実行するための特別なゴルーチンです。g0 ゴルーチンは通常のユーザーゴルーチンとは異なり、非常に大きなスタックサイズを持っており、ランタイムの安定性と効率性を保証します。

  4. ガベージコレクション (Garbage Collection, GC): Goのメモリ管理システムの一部で、不要になったメモリ領域を自動的に解放するプロセスです。GoのGCは並行・並行(concurrent and parallel)に動作し、プログラムの実行を長時間停止させることなくメモリを回収します。GCの実行には、その処理自体が一定のスタック領域を必要とします。

  5. M (Machine) 構造体: Goランタイムのスケジューラにおける「OSスレッド」を表す構造体です。各 M は1つのOSスレッドに対応し、そのスレッド上でゴルーチンを実行します。M 構造体には、現在実行中のゴルーチンや、そのスレッドに関連する様々なランタイム情報が格納されます。このコミットで削除される moreframesize_minalloc フィールドは、この M 構造体の一部でした。

  6. newstack 関数: Goランタイムの内部関数で、ゴルーチンのスタックが不足した場合に、そのスタックを拡張する役割を担います。関数呼び出しによってスタックの使用量が増え、現在のスタックセグメントの限界に近づくと、ランタイムは newstack を呼び出してより大きなスタックセグメントを割り当て、既存のスタック内容を新しいセグメントにコピーします。

技術的詳細

このコミットは、Goランタイムのスタック管理とガベージコレクションの内部実装に関する変更です。

moreframesize_minalloc フィールドは、src/pkg/runtime/runtime.hM 構造体のメンバーとして定義されていました。このフィールドは uint32 型で、GCがスタックを拡張する際に必要となる最小限のフレームサイズを保持する目的で使用されていました。

src/pkg/runtime/stack.c 内の runtime·newstack 関数は、スタック拡張のロジックを実装しています。以前のバージョンでは、runtime·newstackm->moreframesize_minalloc の値を参照し、reflectcall(リフレクションによる関数呼び出し)の場合に、GCが要求する最小スタックサイズを考慮してスタックフレームサイズを調整していました。これは、GCがユーザーゴルーチンのコンテキストで実行される可能性があったため、GCが自身の処理に必要なスタック領域を確保できるようにするための安全策でした。

しかし、Goランタイムの進化により、GCの実行は常に g0 ゴルーチンにオフロードされるようになりました。g0 ゴルーチンは、Goランタイムが起動する際に確保される特別なゴルーチンであり、非常に大きなスタック(通常は数KBからMB単位)を持っています。このため、GCが g0 上で実行される限り、GC処理に必要なスタック領域が不足することはなく、moreframesize_minalloc を介してスタックサイズを動的に調整する必要がなくなりました。

この変更により、M 構造体から moreframesize_minalloc フィールドが削除され、runtime·newstack 関数内の関連するロジックも削除されました。これにより、コードの複雑性が軽減され、ランタイムの効率性が向上します。

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

このコミットによる変更は、主に以下の2つのファイルに集中しています。

  1. src/pkg/runtime/runtime.h:

    • struct M から uint32 moreframesize_minalloc; の行が削除されました。
  2. src/pkg/runtime/stack.c:

    • runtime·newstack 関数のローカル変数宣言から minalloc が削除されました。
    • reflectcall の条件分岐内で minalloc を使用して framesize を調整するロジック、および m->moreframesize_minalloc をリセットするロジックが削除されました。
    • reflectcall の条件式から minalloc == 0 の部分が削除されました。

コアとなるコードの解説

src/pkg/runtime/runtime.h の変更

--- a/src/pkg/runtime/runtime.h
+++ b/src/pkg/runtime/runtime.h
@@ -326,7 +326,6 @@ struct	M
 	void*	tracepc;
 	void	(*waitunlockf)(Lock*);
 	void*	waitlock;
-	uint32	moreframesize_minalloc;
 
 	uintptr	settype_buf[1024];
 	uintptr	settype_bufsize;

この変更は、M 構造体から moreframesize_minalloc フィールドを直接削除しています。これにより、このフィールドがメモリを占有することも、他のコードから参照されることもなくなります。これは、このフィールドが完全に不要になったことを示す最も直接的な変更です。

src/pkg/runtime/stack.c の変更

--- a/src/pkg/runtime/stack.c
+++ b/src/pkg/runtime/stack.c
@@ -173,7 +173,7 @@ runtime·oldstack(void)
 void
 runtime·newstack(void)
 {
-	int32 framesize, minalloc, argsize;
+	int32 framesize, argsize;
 	Stktop *top;
 	byte *stk;
 	uintptr sp;
@@ -196,19 +196,11 @@ runtime·newstack(void)
 		runtime·throw("runtime: stack split argsize");
 	}
 
-	minalloc = 0;
 	reflectcall = framesize==1;
-	if(reflectcall) {
+	if(reflectcall)
 		framesize = 0;
-		// moreframesize_minalloc is only set in runtime·gc(),
-		// that calls newstack via reflect·call().
-		// minalloc = m->moreframesize_minalloc;
-		// m->moreframesize_minalloc = 0;
-		// if(framesize < minalloc)
-		// framesize = minalloc;
-	}
 
-	if(reflectcall && minalloc == 0 && m->morebuf.sp - sizeof(Stktop) - argsize - 32 > gp->stackguard) {
+	if(reflectcall && m->morebuf.sp - sizeof(Stktop) - argsize - 32 > gp->stackguard) {
 		// special case: called from reflect.call (framesize==1)
 		// to call code with an arbitrary argument size,
 		// and we have enough space on the current stack.

この部分の変更は、runtime·newstack 関数内のスタック拡張ロジックから moreframesize_minalloc に関連する処理を削除しています。

  • int32 framesize, minalloc, argsize; から minalloc が削除され、ローカル変数として宣言されなくなりました。
  • minalloc = 0; の初期化が削除されました。
  • if(reflectcall) ブロック内の、m->moreframesize_minallocminalloc に代入し、m->moreframesize_minalloc をリセットし、framesizeminalloc と比較して調整する一連のロジックが完全に削除されました。これは、GCが g0 上で実行されるようになったため、これらのスタック調整が不要になったことを反映しています。
  • if(reflectcall && minalloc == 0 && ...) の条件式から minalloc == 0 の部分が削除されました。これは、minalloc 変数自体がなくなったため、その条件も不要になったためです。

これらの変更により、runtime·newstackmoreframesize_minalloc の概念を完全に無視するようになり、スタック拡張のロジックが簡素化されました。

関連リンク

参考にした情報源リンク