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

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

このコミットは、Goランタイムのガベージコレクション(GC)に関連する不要で混乱を招くコードを削除するものです。具体的には、src/pkg/runtime/mgc0.c 内の addstackroots 関数から、gp->sched.ctxtGobuf.ctxt)を明示的にスキャンするためのコードが削除されています。また、src/pkg/runtime/runtime.hGobuf 構造体内の ctxt フィールドのコメントが更新され、GCがこれをポインタとしてスキャンすることを示しています。

コミット

commit d3be3daafef4b614fc676c807956047976848c7e
Author: Dmitriy Vyukov <dvyukov@google.com>
Date:   Thu Jul 3 22:58:42 2014 +0400

    runtime: delete unnecessary confusing code
    The code in GC that handles gp->gobuf.ctxt is wrong,
    because it does not mark the ctxt object itself,
    if just queues the ctxt object for scanning.
    So the ctxt object can be collected as garbage.
    However, Gobuf.ctxt is void*, so it's always marked and
    scanned through G.
    
    LGTM=khr
    R=golang-codereviews, khr
    CC=golang-codereviews, khr, rsc
    https://golang.org/cl/105490044

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

https://github.com/golang/go/commit/d3be3daafef4b614fc676c807956047976848c7e

元コミット内容

このコミットは、Goランタイムのガベージコレクション(GC)における、gp->gobuf.ctxt の処理に関するコードを削除します。コミットメッセージによると、削除されたコードは「間違っており」、ctxt オブジェクト自体をマークせず、スキャンするためにキューに入れるだけだったため、ctxt オブジェクトがガベージとして収集される可能性があったと説明されています。しかし、Gobuf.ctxtvoid* 型であるため、常に G (goroutine) を通じてマークされ、スキャンされるため、削除されたコードは不要であると判断されました。

変更の背景

Goのガベージコレクタは、到達可能なオブジェクトを特定し、それらが誤って収集されないようにする役割を担っています。このプロセスでは、プログラムの「ルート」(グローバル変数、ゴルーチンのスタック、レジスタなど)をスキャンして、到達可能なオブジェクトをマークします。

Gobuf は、ゴルーチンの実行コンテキスト(スタックポインタ sp、プログラムカウンタ pc、そして ctxt フィールドなど)を保存および復元するために使用される構造体です。ctxt フィールドは void* (Goでは unsafe.Pointer) 型であり、任意のデータ型を指すことができます。特に、ヒープに割り当てられた関数値(funcval)へのポインタを保持する可能性があります。

コミットメッセージが示唆するように、以前のGCコードには gp->gobuf.ctxt を処理する際に誤りがありました。このコードは ctxt オブジェクト自体をマークせず、単にスキャンキューに入れるだけだったため、GCが ctxt が指すオブジェクトを到達可能と正しく認識できない可能性がありました。しかし、実際には Gobuf.ctxtG (ゴルーチン構造体) の一部として、GCによって常にルートとして扱われ、スキャンされていました。つまり、削除されたコードは冗長であり、むしろ混乱を招くものでした。この変更は、GCの正確性を維持しつつ、コードベースを簡素化することを目的としています。

前提知識の解説

  • Goランタイム: Goプログラムの実行を管理する低レベルのシステム。ガベージコレクション、スケジューリング、メモリ管理などが含まれます。
  • ガベージコレクション (GC): プログラムが不要になったメモリを自動的に解放するプロセス。GoのGCは並行マーク&スイープ方式を採用しており、プログラムの実行と並行して動作します。
  • ルート (GC Roots): GCが到達可能性を判断する際の開始点となるオブジェクト。これには、グローバル変数、実行中のゴルーチンのスタック、CPUレジスタなどが含まれます。ルートから辿れるオブジェクトは到達可能とみなされ、そうでないオブジェクトはガベージとして収集されます。
  • G 構造体: Goランタイムにおけるゴルーチンを表す構造体。ゴルーチンのスタック情報、スケジューリング情報、Gobuf などが含まれます。
  • Gobuf 構造体: ゴルーチンの実行コンテキスト(レジスタ値、スタックポインタ、プログラムカウンタなど)を保存するための構造体。ゴルーチンの切り替え(コンテキストスイッチ)時に使用されます。
  • Gobuf.ctxt: Gobuf 構造体内のフィールドで、void* (C言語のポインタ型) または unsafe.Pointer (Go言語のポインタ型) として定義されています。このフィールドは、特定のコンテキスト情報(例えば、クロージャの環境ポインタなど)を保持するために使用されます。GCは、このフィールドが指す可能性のあるヒープ上のオブジェクトもスキャンする必要があります。
  • addstackroots 関数: GoランタイムのGCの一部で、ゴルーチンのスタックをスキャンし、スタック上のポインタをGCルートとして追加する役割を持つ関数。これにより、スタックから到達可能なオブジェクトがマークされます。

技術的詳細

このコミットの核心は、GoのGCが Gobuf.ctxt をどのように扱うかという理解の修正にあります。

  1. Gobuf.ctxt の性質: Gobuf.ctxtvoid* 型であり、これはGoの unsafe.Pointer に相当します。この型は、任意のメモリ位置を指すことができる汎用ポインタです。GoのGCは、このようなポインタがヒープ上のオブジェクトを指している可能性があるため、GCルートとして特別に扱います。
  2. GCのルートスキャン: GoのGCは、ゴルーチン(G 構造体)をスキャンする際に、その内部に含まれるすべてのポインタフィールドを自動的にスキャンします。これには、G 構造体内に埋め込まれている Gobuf 構造体、そしてその中の ctxt フィールドも含まれます。つまり、Gobuf.ctxt が指すオブジェクトは、G を通じて常に到達可能としてマークされ、スキャンされることが保証されています。
  3. 削除されたコードの冗長性: 以前の addstackroots 関数には、gp->sched.ctxt (これは Gobuf.ctxt の別名) がゼロでない場合に、そのコンテキストオブジェクトをスキャンキューに追加する明示的なロジックがありました。しかし、上述のように Gobuf.ctxtG 構造体の一部として既にGCによってスキャンされるため、この明示的な追加は冗長でした。
  4. 削除されたコードの誤り: コミットメッセージが指摘するように、削除されたコードは「間違って」いました。それは ctxt オブジェクト自体をマークするのではなく、単にスキャンキューに入れるだけでした。これは、GCが ctxt が指すオブジェクトの到達可能性を正しく判断できない可能性をはらんでいました。しかし、G を通じたスキャンが正しく行われていたため、実際には問題は発生していなかったと考えられます。
  5. コードの簡素化と明確化: このコミットは、冗長で潜在的に誤解を招くコードを削除することで、GCのロジックを簡素化し、より明確にしています。Gobuf.ctxtvoid* であるためGCが自動的にスキャンするという事実を強調するために、runtime.h のコメントが更新されました。

この変更は、GoランタイムのGCがどのようにポインタを追跡し、メモリの安全性を確保しているかについての深い理解に基づいています。

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

src/pkg/runtime/mgc0.c

addstackroots 関数から以下のコードブロックが削除されました。

-	void *base;
-	uintptr size;
...
-		// For function about to start, context argument is a root too.
-		if(gp->sched.ctxt != 0 && runtime·mlookup(gp->sched.ctxt, &base, &size, nil))
-			enqueue1(wbufp, (Obj){base, size, 0});

この削除されたコードは、gp->sched.ctxt (すなわち Gobuf.ctxt) が指すオブジェクトを明示的にGCのワークキューに追加しようとしていました。

src/pkg/runtime/runtime.h

Gobuf 構造体内の ctxt フィールドのコメントが変更されました。

--- a/src/pkg/runtime/runtime.h
+++ b/src/pkg/runtime/runtime.h
@@ -213,7 +213,7 @@ struct	Gobuf
 	uintptr	sp;
 	uintptr	pc;
 	G*	g;
-	void*	ctxt;
+	void*	ctxt; // this has to be a pointer so that GC scans it
 	uintreg	ret;
 	uintptr	lr;
 };

新しいコメント「// this has to be a pointer so that GC scans it」は、ctxt がポインタ型であることの重要性、すなわちGCがそれをスキャンする必要があることを明確に示しています。

コアとなるコードの解説

src/pkg/runtime/mgc0.caddstackroots 関数は、GCのマークフェーズ中にゴルーチンのスタックをスキャンし、スタック上のポインタをGCルートとして登録する役割を担っていました。削除されたコードは、gp->sched.ctxt が指すメモリ領域を明示的に検索し、その情報をGCのワークキューに追加しようとしていました。

しかし、GoのGCは、G 構造体(ゴルーチンを表す)をスキャンする際に、その内部に含まれるすべてのポインタフィールド(Gobuf 構造体、そしてその中の ctxt フィールドを含む)を自動的に追跡します。つまり、Gobuf.ctxt が指すオブジェクトは、G を通じて既にGCによって到達可能としてマークされ、スキャンされるため、addstackroots 内の明示的な処理は冗長であり、不要でした。

src/pkg/runtime/runtime.h の変更は、この理解を反映しています。Gobuf.ctxtvoid* (ポインタ) であるという事実が、GCがそれをスキャンする理由であることを明確にするコメントが追加されました。これは、このフィールドがGCにとって特別な意味を持つことを開発者に示唆しています。

この変更は、GoランタイムのGCの内部動作に関する深い知識に基づいており、コードの簡素化と正確性の向上に貢献しています。

関連リンク

  • Goのガベージコレクションに関する公式ドキュメントやブログ記事
  • Goの unsafe.Pointer に関するドキュメント
  • Goランタイムのソースコード(特に runtime パッケージとGC関連ファイル)

参考にした情報源リンク

  • https://github.com/golang/go/commit/d3be3daafef4b614fc676c807956047976848c7e
  • Web検索結果: "Go runtime GC Gobuf ctxt void* scanning" (特に、Gobufctxt、GCルートスキャンに関する情報源)
    • nutanix.com (https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEwR0i9Tl4F3AYYp5G89okEVkZFDQPFxSG1b8lZBN9IzG9wLNXqGqHVFVW3AncjEM9EU_MUCptThioJv4vfe-bEZprMXUUEe00SMoCR1MwjXllJ6j-QVjPOXYUN3Eupqepes6Pm0sJ-VxeKa0d7G_Ox4n704yMPg4PNwuFmi2O6jWvCYiarFVFE0DH_v9FLkU-YKUVnpcLwe4iIaPR6fke4pFcVgm-E-Te5zt7Hsg==)
    • golang.org (https://vertexaisearch.cloud.com/grounding-api-redirect/AUZIYQEXrSCEx9ruxlx7onGsA9XMqbEivAHBG7rK7aPNP5OPZYKKgwkjJCsQCUf0v6w0SnTMN7zfxuU-BomAapn-o10sgaDQWR5VZhxwKydmvntRfWP5ptrkq0LHHlUUKmNA)
    • medium.com (https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQECMsyG_lDc1Ct-ATByxswe2m3s9PWYj0O3RifaFV23fatTfRa816rBeDVXoRXsS4yFQKihKpwUNmVWURhymQP8EoPEBsF8GgUGNdQ4IK2t-cPRjNE3fSoNRLltyz3Czd1vq6IyVIdgFs-CdLlFnd7AsJJQKAByy5DwemMmDs874LmuePw045UJsumQhXOQE8CoTidRu9ziYtIknd6YCq9OCwKa55DQCaOhtwK6-anO9eiiu1JrUa12PyJgbzv5x3qv4_cqqx0=)
    • sobyte.net (https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGNFjQQdRX9EuW0S8TNQxG2R5Nurq9-0e9O7C1keYvnrTrcC-fEfxDZSYzNjscm5NjGB2g7Ls6Cs-x_DQvuF33lDDRqmjYpWugb3Q8b7kcruB25IJSgSAGXAMU8KIHrQiBvmDdPYw==)
    • goperf.dev (https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQFX8S7kTpwL2G2fJOEWZ5rhvUvuwzk97bjVVVBvLlk7gZfl1X_Ils0qAd-buvHWL_PzRqGkNfhbHHPp8zjXrZJdDiJGLvfgCMUUxwxHaIx_pfcvY5MgnFIwYVx2TBmgKOBO_-6z)
    • medium.com (https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEHBsOdBc7elrScrv_QPSBfS6eTmNpe2UtOVwoCiokQj_744Gv_ZkNKQXSSfB3wGXCSXsdXuXxaJxO10t3fpoCJtzJb7Jnmdkl25L3fZMa60laOg2OZq4EGXyRVvy48PdlL8Dc5ShyA4Bbhr-HnrTTsj0Xkd-nLa2QgMiscbfnnGsp62tptUWOIm2Ia7AGutezFGGEWrKeuPQ==)