[インデックス 19071] ファイルの概要
このコミットは、GoランタイムにおけるGOTRACEBACK
環境変数の設定値の取得を最適化することを目的としています。特に、gotraceback
関数の呼び出しが頻繁に行われるガベージコレクション中に、環境変数の読み込みと解析(getenv
とatoi
の呼び出し)によるオーバーヘッドを削減するため、設定値をキャッシュするメカニズムを導入しています。これにより、特にPlan 9のような特定の環境で発生していた潜在的な問題(getenv
がmalloc
を呼び出すことによるGC中のメモリ割り当て)を緩和し、他のシステムでもわずかながらパフォーマンスを向上させます。
コミット
runtime: cache gotraceback setting
On Plan 9 gotraceback calls getenv calls malloc, and we gotraceback
on every call to gentraceback, which happens during garbage collection.
Honestly I don't even know how this works on Plan 9.
I suspect it does not, and that we are getting by because
no one has tried to run with $GOTRACEBACK set at all.
This will speed up all the other systems by epsilon, since they
won't call getenv and atoi repeatedly.
LGTM=bradfitz
R=golang-codereviews, bradfitz, 0intro
CC=golang-codereviews
https://golang.org/cl/85430046
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/5556bfa9c736f63ae18ec0ab8ef9b6a986e32ef3
元コミット内容
commit 5556bfa9c736f63ae18ec0ab8ef9b6a986e32ef3
Author: Russ Cox <rsc@golang.org>
Date: Tue Apr 8 22:35:41 2014 -0400
runtime: cache gotraceback setting
On Plan 9 gotraceback calls getenv calls malloc, and we gotraceback
on every call to gentraceback, which happens during garbage collection.
Honestly I don't even know how this works on Plan 9.
I suspect it does not, and that we are getting by because
no one has tried to run with $GOTRACEBACK set at all.
This will speed up all the other systems by epsilon, since they
won't call getenv and atoi repeatedly.
LGTM=bradfitz
R=golang-codereviews, bradfitz, 0intro
CC=golang-codereviews
https://golang.org/cl/85430046
---
src/pkg/runtime/proc.c | 4 ++++\n src/pkg/runtime/runtime.c | 35 ++++++++++++++++++++++++-----------\n 2 files changed, 28 insertions(+), 11 deletions(-)\n
diff --git a/src/pkg/runtime/proc.c b/src/pkg/runtime/proc.c
index 2ab54be70c..6b5c031c87 100644
--- a/src/pkg/runtime/proc.c
+++ b/src/pkg/runtime/proc.c
@@ -155,6 +155,10 @@ runtime·schedinit(void)
// in a fault during a garbage collection, it will not
// need to allocated memory.
runtime·newErrorCString(0, &i);\n+\t\n+\t// Initialize the cached gotraceback value, since\n+\t// gotraceback calls getenv, which mallocs on Plan 9.\n+\truntime·gotraceback(nil);\n \n runtime·goargs();
runtime·goenvs();
diff --git a/src/pkg/runtime/runtime.c b/src/pkg/runtime/runtime.c
index d995bf97ae..725c6d838e 100644
--- a/src/pkg/runtime/runtime.c
+++ b/src/pkg/runtime/runtime.c
@@ -20,22 +20,35 @@ enum {\n int32
runtime·gotraceback(bool *crash)\n {\n+\t// Keep a cached value to make gotraceback fast,\n+\t// since we call it on every call to gentraceback.\n+\t// The cached value is a uint32 in which the low bit\n+\t// is the \"crash\" setting and the top 31 bits are the\n+\t// gotraceback value.\n+\tstatic uint32 cache = ~(uint32)0;\n \tbyte *p;\n+\tuint32 x;\n \n \tif(crash != nil)\n \t\t*crash = false;\n-\tp = runtime·getenv(\"GOTRACEBACK\");\n-\tif(p == nil || p[0] == \'\\0\') {\n-\t\tif(m->traceback != 0)\n-\t\t\treturn m->traceback;\n-\t\treturn 1;\t// default is on\n-\t}\n-\tif(runtime·strcmp(p, (byte*)\"crash\") == 0) {\n-\t\tif(crash != nil)\n-\t\t\t*crash = true;\n-\t\treturn 2;\t// extra information\n+\tif(m->traceback != 0)\n+\t\treturn m->traceback;\n+\tx = runtime·atomicload(&cache);\n+\tif(x == ~(uint32)0) {\n+\t\tp = runtime·getenv(\"GOTRACEBACK\");\n+\t\tif(p == nil)\n+\t\t\tp = (byte*)\"\";\n+\t\tif(p[0] == \'\\0\')\n+\t\t\tx = 1<<1;\n+\t\telse if(runtime·strcmp(p, (byte*)\"crash\") == 0)\n+\t\t\tx = (2<<1) | 1;\n+\t\telse\n+\t\t\tx = runtime·atoi(p)<<1;\t\n+\t\truntime·atomicstore(&cache, x);\n \t}\n-\treturn runtime·atoi(p);\n+\tif(crash != nil)\n+\t\t*crash = x&1;\n+\treturn x>>1;\n }\n \n int32
変更の背景
このコミットの主な背景には、Goランタイムがスタックトレースを生成する際に使用するGOTRACEBACK
環境変数の設定値の取得方法に起因するパフォーマンスと安定性の問題がありました。
特に、Plan 9オペレーティングシステム上では、getenv
(環境変数を取得する関数)が内部でメモリ割り当て(malloc
)を呼び出すという特性がありました。Goランタイムは、ガベージコレクション(GC)の実行中にgentraceback
(トレースバックを生成する関数)を頻繁に呼び出し、その過程でgotraceback
関数が呼ばれます。もしgotraceback
が呼ばれるたびにgetenv
がmalloc
を呼び出すと、GC中にメモリ割り当てが発生するという、非常に危険でデッドロックを引き起こしやすい状況が生じます。コミットメッセージの著者であるRuss Cox氏も、「正直なところ、Plan 9でこれがどのように機能しているのかさえわからない」と述べており、$GOTRACEBACK
が設定されていないために問題が顕在化していなかった可能性を指摘しています。
他のシステム(Linux, macOSなど)では、getenv
がmalloc
を呼び出すことは一般的ではありませんが、それでもgotraceback
が呼ばれるたびに環境変数を読み込み、文字列を整数に変換するatoi
を呼び出すことは、わずかながらオーバーヘッドとなります。このコミットは、これらの繰り返し発生する呼び出しを避けることで、すべてのシステムでパフォーマンスを向上させることを目指しました。
しかし、このコミットのレビュー過程では、0intro
氏が「GOTRACEBACK
はgetenv
がmalloc
を呼び出すという根本的な問題のために、Plan 9ではこれまで正しく機能したことがなかった」と指摘しています。このコミットによるキャッシュ導入は、この根本問題を解決するものではなく、むしろその存在を浮き彫りにしました。Russ Cox氏も、getenv
自体がmalloc
を避けるように変更される必要がある(例:sbrk
を使用するか、静的バッファを使用する)と認めています。
また、このコミットが提出された直後、linux-386
ビルダで問題を引き起こしたという報告もあり、変更が意図しない副作用をもたらす可能性も示唆されました。
前提知識の解説
Goランタイム (Go Runtime)
Goランタイムは、Goプログラムの実行を管理するシステムです。これには、ガベージコレクション(GC)、ゴルーチン(軽量スレッド)のスケジューリング、メモリ管理、システムコールとの連携などが含まれます。Goプログラムは、OS上で直接実行されるのではなく、このランタイム上で動作します。
GOTRACEBACK環境変数
GOTRACEBACK
は、Goプログラムがパニック(実行時エラー)を起こした際に生成されるスタックトレースの詳しさを制御する環境変数です。
GOTRACEBACK=0
またはnone
: スタックトレースを抑制し、パニックメッセージのみを表示します。GOTRACEBACK=1
またはsingle
(デフォルト): パニックを引き起こしたゴルーチンのスタックトレースを表示します。GOTRACEBACK=2
またはsystem
: ランタイム関数を含む、より詳細なスタックトレースを表示します。GOTRACEBACK=all
: すべてのユーザー作成ゴルーチンのスタックトレースを表示します。GOTRACEBACK=crash
: オペレーティングシステム固有のクラッシュ(Unix系ではSIGABRT
など)を引き起こし、コアダンプを生成しようとします。
スタックトレース (Stack Trace)
スタックトレースは、プログラムがエラーやパニックを起こした時点での関数呼び出しの履歴です。どの関数がどの関数を呼び出し、最終的にエラーが発生したのかを示すことで、問題の原因を特定するのに役立ちます。
ガベージコレクション (Garbage Collection, GC)
ガベージコレクションは、プログラムが動的に確保したメモリのうち、もはや使用されていない(参照されていない)領域を自動的に解放するプロセスです。GoのGCは、プログラムの実行中にバックグラウンドで動作し、メモリリークを防ぎ、開発者が手動でメモリを管理する手間を省きます。GCの実行中は、プログラムの実行が一時停止したり、パフォーマンスに影響を与えたりすることがあります。
Plan 9
Plan 9 from Bell Labsは、Unixの設計思想をさらに推し進めた分散オペレーティングシステムです。その特徴の一つに、すべてのリソース(ファイル、デバイス、ネットワーク接続、さらには環境変数)がファイルシステムとして表現されるという思想があります。例えば、環境変数は/env
ディレクトリ内のファイルとして扱われます。この特性が、getenv
の動作に影響を与えます。
getenv
とmalloc
getenv
: C言語の標準ライブラリ関数で、指定された環境変数の値を取得します。通常、この関数は環境変数の値を指すポインタを返しますが、そのメモリはシステムによって管理されており、ユーザーが解放すべきではありません。malloc
: C言語の標準ライブラリ関数で、指定されたサイズのメモリブロックをヒープから動的に割り当てます。
一般的なシステムでは、getenv
が直接malloc
を呼び出すことは稀ですが、Plan 9のように環境変数がファイルとして扱われるシステムでは、環境変数の値を読み込むためにファイルI/Oやバッファリングが必要となり、その過程でメモリ割り当て(malloc
)が発生する可能性があります。ガベージコレクション中にmalloc
が呼ばれることは、GCの内部状態と競合し、デッドロックやクラッシュの原因となる非常に危険な状況です。
atoi
atoi
は "ASCII to Integer" の略で、C言語の標準ライブラリ関数の一つです。文字列を整数値に変換するために使用されます。GOTRACEBACK
環境変数の値は文字列として設定されるため、Goランタイムがその値を数値として解釈する際にatoi
のような変換処理が必要になります。
技術的詳細
このコミットは、GOTRACEBACK
環境変数の値をキャッシュすることで、runtime·gotraceback
関数の呼び出しコストを削減します。
-
キャッシュの導入:
runtime·gotraceback
関数内にstatic uint32 cache
という静的変数が導入されました。この変数は、GOTRACEBACK
の設定値を一度読み込んだら、それを記憶しておくためのキャッシュとして機能します。初期値は~(uint32)0
(すべてのビットが1)に設定されており、これはキャッシュがまだ初期化されていないことを示します。 -
キャッシュ値のエンコーディング:
uint32
型のcache
変数には、GOTRACEBACK
の数値設定(例: 1, 2, allなど)と、crash
フラグ(GOTRACEBACK=crash
が設定されているかどうか)の両方がエンコードされます。- 最下位ビット(
x&1
)がcrash
フラグを表します。1
であればcrash
モード、0
であればそれ以外です。 - 残りの31ビット(
x>>1
)がGOTRACEBACK
の数値設定を表します。 例えば、GOTRACEBACK=1
の場合は1<<1
、GOTRACEBACK=crash
の場合は(2<<1) | 1
(値は2でcrash
フラグが立つ)のようにエンコードされます。
- 最下位ビット(
-
キャッシュの利用ロジック:
runtime·gotraceback
が呼び出されると、まずruntime·atomicload(&cache)
を使ってキャッシュの値をアトミックに読み込みます。- もし読み込んだ値が初期値
~(uint32)0
であれば、キャッシュが未初期化であると判断し、実際にruntime·getenv("GOTRACEBACK")
を呼び出して環境変数の値を読み込みます。 - 読み込んだ環境変数の値に基づいて、適切な数値と
crash
フラグを計算し、runtime·atomicstore(&cache, x)
を使ってアトミックにキャッシュに書き込みます。アトミック操作を使用することで、複数のゴルーチンが同時にgotraceback
を呼び出しても、キャッシュの整合性が保たれます。 - キャッシュが初期化済みであれば、環境変数を再度読み込むことなく、キャッシュされた値から
crash
フラグとGOTRACEBACK
の数値を抽出し、それを返します。
- もし読み込んだ値が初期値
-
初期化時のキャッシュ事前設定:
src/pkg/runtime/proc.c
のruntime·schedinit
関数(ランタイムの初期化処理)内で、runtime·gotraceback(nil)
が呼び出されるようになりました。これは、ランタイム起動時に一度gotraceback
関数を呼び出すことで、Plan 9におけるgetenv
のmalloc
呼び出し問題を回避しつつ、キャッシュを事前に設定しておくためのものです。これにより、GC中に初めてgotraceback
が呼ばれる際にgetenv
が呼び出されることを防ぎます。 -
パフォーマンスへの影響: この変更により、
gotraceback
が頻繁に呼び出される場合(特にGC中)、環境変数の読み込みと解析のオーバーヘッドが初回のみに限定され、以降は高速なキャッシュアクセスに置き換わります。これにより、全体的なパフォーマンスがわずかに向上します。 -
Plan 9の問題の再確認: このコミットは、Plan 9における
getenv
がmalloc
を呼び出すという根本的な問題を解決するものではありませんでした。むしろ、キャッシュを導入してもなお、getenv
がmalloc
を呼び出すこと自体が問題であり、getenv
の実装自体を変更する必要があることが議論で明らかになりました。 -
ビルドの不具合: このコミットが提出された後、
linux-386
ビルダで問題が発生したと報告されました。これは、変更が特定のアーキテクチャや環境で予期せぬ副作用を引き起こす可能性を示しています。
コアとなるコードの変更箇所
このコミットによる主要なコード変更は、以下の2つのファイルに集中しています。
-
src/pkg/runtime/proc.c
:runtime·schedinit
関数内に、runtime·gotraceback(nil);
という行が追加されました。これは、ランタイムの初期化時にgotraceback
関数を一度呼び出し、GOTRACEBACK
環境変数の値をキャッシュに事前設定するためのものです。
-
src/pkg/runtime/runtime.c
:runtime·gotraceback
関数の実装が大幅に変更されました。static uint32 cache = ~(uint32)0;
という静的変数が追加され、GOTRACEBACK
設定値のキャッシュとして機能します。- 環境変数を読み込む前にキャッシュをチェックし、未初期化の場合のみ
runtime·getenv
とruntime·atoi
を呼び出すロジックが追加されました。 - キャッシュへの読み書きには
runtime·atomicload
とruntime·atomicstore
が使用され、アトミック性が保証されています。 GOTRACEBACK
の数値とcrash
フラグを単一のuint32
値にエンコード・デコードするロジックが実装されました。
コアとなるコードの解説
src/pkg/runtime/runtime.c
の runtime·gotraceback
関数
int32
runtime·gotraceback(bool *crash)
{
// Keep a cached value to make gotraceback fast,
// since we call it on every call to gentraceback.
// The cached value is a uint32 in which the low bit
// is the "crash" setting and the top 31 bits are the
// gotraceback value.
static uint32 cache = ~(uint32)0; // キャッシュ変数、初期値は未初期化を示す
byte *p;
uint32 x;
if(crash != nil)
*crash = false; // crashフラグの初期化
if(m->traceback != 0) // m->tracebackが設定されている場合はそれを返す(デバッグ用など)
return m->traceback;
x = runtime·atomicload(&cache); // キャッシュの値をアトミックに読み込む
if(x == ~(uint32)0) { // キャッシュが未初期化の場合
p = runtime·getenv("GOTRACEBACK"); // 環境変数を読み込む
if(p == nil)
p = (byte*)""; // 環境変数が設定されていない場合は空文字列として扱う
if(p[0] == '\0') // 空文字列の場合(デフォルト値)
x = 1<<1; // デフォルト値1をエンコード (1 << 1 = 2)
else if(runtime·strcmp(p, (byte*)"crash") == 0) // "crash"の場合
x = (2<<1) | 1; // 値2をエンコードし、crashフラグを立てる (2 << 1 | 1 = 5)
else
x = runtime·atoi(p)<<1; // 数値の場合、それをエンコード
runtime·atomicstore(&cache, x); // 計算した値をアトミックにキャッシュに保存
}
if(crash != nil)
*crash = x&1; // キャッシュされた値からcrashフラグをデコード
return x>>1; // キャッシュされた値からGOTRACEBACKの数値をデコードして返す
}
このコードは、GOTRACEBACK
環境変数の値を効率的に取得するためのキャッシュメカニズムを実装しています。
static uint32 cache = ~(uint32)0;
:cache
変数は、runtime·gotraceback
関数が呼び出されるたびに再初期化されることなく、その状態を保持します。~(uint32)0
という初期値は、すべてのビットが1であるuint32
の最大値であり、これは「キャッシュがまだ設定されていない」という特別な意味を持ちます。x = runtime·atomicload(&cache);
: 複数のゴルーチンが同時にruntime·gotraceback
を呼び出す可能性があるため、キャッシュの読み込みはアトミックに行われます。これにより、データ競合を防ぎます。if(x == ~(uint32)0)
: キャッシュが未初期化の場合、実際の環境変数読み込みと解析が行われます。p = runtime·getenv("GOTRACEBACK");
: 環境変数の値を取得します。if(p == nil) p = (byte*)"";
: 環境変数が設定されていない場合は、空文字列として扱います。if(p[0] == '\0') x = 1<<1;
: 環境変数が空の場合(デフォルトの動作)、GOTRACEBACK=1
を意味する値をx
に設定します。1
を左に1ビットシフトすることで、最下位ビットをcrash
フラグ用に空けています。else if(runtime·strcmp(p, (byte*)"crash") == 0) x = (2<<1) | 1;
: 環境変数が"crash"
の場合、GOTRACEBACK=2
を意味する値を設定し、最下位ビットを1
にすることでcrash
フラグを立てます。else x = runtime·atoi(p)<<1;
: それ以外の場合(数値が設定されている場合)、atoi
で文字列を整数に変換し、同様に左に1ビットシフトしてx
に設定します。
runtime·atomicstore(&cache, x);
: 計算されたGOTRACEBACK
の値をアトミックにキャッシュに保存します。if(crash != nil) *crash = x&1;
: キャッシュされた値x
の最下位ビットをマスクすることで、crash
フラグを抽出します。return x>>1;
: キャッシュされた値x
を右に1ビットシフトすることで、crash
フラグを除いたGOTRACEBACK
の数値設定を返します。
src/pkg/runtime/proc.c
の runtime·schedinit
関数
// ...
// Initialize the cached gotraceback value, since
// gotraceback calls getenv, which mallocs on Plan 9.
runtime·gotraceback(nil);
// ...
この変更は、Goランタイムの初期化フェーズであるruntime·schedinit
において、runtime·gotraceback(nil)
を明示的に呼び出すものです。これにより、プログラムの実行が本格的に始まる前にGOTRACEBACK
のキャッシュが一度初期化されます。特にPlan 9のようにgetenv
がmalloc
を呼び出す環境では、この事前初期化によって、ガベージコレクション中にgotraceback
が初めて呼び出される際にmalloc
が発生するのを防ぎ、潜在的なデッドロックやクラッシュのリスクを軽減します。
関連リンク
- Go CL 85430046: https://golang.org/cl/85430046
参考にした情報源リンク
- Go
GOTRACEBACK
環境変数に関する情報:- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGf1zUDdge30E_srr-qAqQ1IGtsC1BGodRb6aDPA9MQwJ_XigMcHHtKassD4hzZ5AvnQACFcXBj7SI3oyLPy7XeDl175EE8b4VlFYnKAWaUcmFhPhuQzg0XQAGVc2CnCbWH2Mr50iwCK-CCg0VCkqA1apw2vlSgonYnw0t2Ge_694loudwWyu-85sUMlYWhRD_EzqIt
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGEHIhYX54-KWDtWEu4m3B7evoQBkdLVs8GYldD8bbi4uFcQ4BizDitvcSvF8HEbwUvqAGJh57CKxOmwVxAkSrjZ6dSMuap1jdm_sXC1Z--cIjI5uCH
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGd4TsAKWPoa6zUTwQzAFbzdy5S_QObyxAlSHOqDOpUnCm-bOmiaPtFyYPNRQBKlQTUHlNgJcPBWvpPn15_uWpxyaDYwgnwr8MRfljyGLsosCRuBPioF-DrH21EJWOpRITsthBmVvqCvUq2u1vQF5m72TrZ-e7SPuWy_hMSR8TH2tZlgwMLQrmjTQXJjo7S3AW1rjp0=
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQE_sSCNfsNnLiykMwW2o-EohhAis_ELzquJwwf72vLtvINOgs_hQ51fPxOKQHMvCbhF5jyAPDzw1qlelc_otoPzCRDtH30M8yR0dUdCLwWmBS87Cz9LZDqhMeuM
- Plan 9 環境変数とファイルシステム:
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEGRotxuI6EypSwJ1WF5OXZN7KvpCkWYRK5FpsGhWxckd7pSxOGZoyyykhtD9P_MMJLAqUBxeASxlY0r1qRZrCW07iRSy9N1W_A5Vozv9gGk1NTs8M=
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHL62tlsCvr5TWKMZo0DhudY-iypMYBq9xs0saxmwKQNJAczOgU0JAfaF_IkDbZulDmFfR-gmsG611ZGv3GQrAucBQvGyjK9KNTMq8SYytNAOzWMo-5Of3ZjVTbK8yGN2OsB03hBHhthCvPvlUhmgOu1kstDuu6
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQFnWX-R5DRIXWwOdhOf1mb2jBMl4689shCrW389Kr-y7uwOt20giXua2D5fgK5oAVA5MqE4GNqjIo4XvkPGtScN8HhH0_lYnWaFiNYTf7L-dB4Eb0noqg5PjxtbV32mCB3cXQaN2lj_Ex7VQh8W6Et1Dh_gVH4kmkZmrBtscdra281MO1F93HYeRQhrO-xM6v51cdnUcOdJUCPz5OVUCid1Fd3DYbagOuVEwKHHWQ==
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQEzErJufZShi0dUzpsKzo8k7fjXk_9PzUAP5qiauAxbJ5j2OZUv1b-wIx4ZenHeKL9zxb4qzRlqqj8HW-u5ijASZvG5qdrqGoxjZbzOASW01w8kuru-_GGJdyAx6EeA2K0JOw==
os.Getenv
とgetenv
:- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQECQ5zaNYJWHDwpNIbqmydGk9BLKCShGwj5hz6CgfGFlu4UDExXDNJne6TPyYb4SprZFm3Hxnc3H5sbOpkwwQVOECuTbEucqOXH-zdAbqzpmNve3Tl4vOlh6zFFbuQz7w9XV5-oAwYVVw==
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGlT0G5bVp5C0K4ohQ6RCNVm3si1FnMSPDeZx-WDCL4Hl76iK9Y6jSGoxIWLc6N0PDheL9THFBTxgZcpi2YPFn2iHSjDJa_NZhxCVsrne_Tq_7lKpM2LDkLDAY09LL3M8ItwKhIMv02WTkvIjBOSi-c9EOblN2VBs-6issq07OGUhMTSlPGRP9x
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHfw088frRl_q-vz1WCDhxXL_F6Yn15nadr3QCZnTj7np2tMa0QvqbR4vyx1SdcSzoyIr18pPF08wfCu9wFuI_oEjE_ky0WI_8PJXFr2fDjn1loa9zsu7wb1wm26eSFq3e_JKuJkP5oPe2k9CwJlIPW0GUB5J4AIilpxDVPEuRyfQb9ds80z9axx3JrelHMZAVo5qOdoY2ybk-wV7ySn-RMg3wrVG0mbxiCkQ==
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQF640vDIjzvagtaiv-pgSxmU-ElsjRwq1u7dwy0LDHS7e2HXZS_9CY14A89HUh_lunRNgX2ZYbVagxx9p1_YAWAE8ndhx9mkr467JEUCSGeTiXthQZPocr8t-WtJlH1Q0vUIrjDPEEX4hP-M6-uIEOekPZnQoybb0nVeOFfPcDV--Sw37h3Io5jzk7wTLf3ct8m_U=
- Go メモリ管理と
malloc
:- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHnebDMPNa5YAi0eesiFSBoVx8S1jysJQHVwyQdYdOvQ7KgAsX32mLpk-_W1oePile-EuFNQb8sxbDyboXyD3DOvaNRyLJnMobvQG666iJErAQfGBDmwHhHaiisivt2m9eISU49LB_RtNhJSdc9Dw==
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQFSE6x1tkVd9CpuJkBHozTseTt0h9egP4fuPQYsbi9jbqzAC-JZVLcj2tooJ2IKZ39zCvRH9fZU79pAceViSiigGFZ6K8figkmRNaIGHLfC8Yj6fA86lLxY__aGeV1qaP6uzSiSMuJAtQz1AsVPcR2eBWFWp9cRCQ==
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHce1R9zIw5_mpKJk_8UO7j-N1OP9j844Ir2H2ge3JInYVaXttbN-VGkCwJMeoF3S9S2_G4cjrE9XrgOGW4GEbWNbkLKnh7vllZrqKhcIO_wZkCM0m4ck--WfAf1yXlKfCNuyCgk89_iZYgu02EkksbdxUv-F4fC8=
- https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQHrb_ZkISkJs7n-5Nz2NT15ogK8A8JqS3KoTzRnSSOnllyvxi7GInMTje6IUz5Luk2lvMto4dK7MDX89yfAUblv7EAk21bxy_wSueup2P71G0qPQ7ZEleYetcMhZyQ_GMFE8FPKUP6sS2EzQRVadSalCctnj62y5KguPQifnTVKoix3kC7pZrt0x_9rnrPXDSVtJavicalCPlXkKtSglNX