[インデックス 19008] ファイルの概要
このコミットは、Goコンパイラ(cmd/gc
)における一時変数(temporary variables)のライフタイムを短縮し、ガベージコレクション(GC)の効率を向上させることを目的としています。主に以下のファイルが変更されています。
src/cmd/gc/closure.c
: クロージャおよび部分適用された関数呼び出しにおける一時変数の管理方法を更新。src/cmd/gc/esc.c
: エスケープ解析において、複合リテラルや部分適用された関数呼び出しが非エスケープ引数として渡される場合の一時変数の扱いを改善。src/cmd/gc/order.c
: 一時変数のクリーンアップロジックの核心部分。if
、for
、select
、&&
、||
などの制御構造における一時変数の積極的な解放を導入。select
文の一時変数生成ロジックをselect.c
からこちらに移動。src/cmd/gc/range.c
:range
文におけるイテレータ用一時変数の管理を更新。src/cmd/gc/select.c
:select
文の処理から一時変数管理ロジックの多くをorder.c
に委譲し、1エントリのselect
最適化を再有効化。src/cmd/gc/sinit.c
: スライスリテラルにおける一時変数の初期化を更新。src/cmd/gc/subr.c
:localexpr
関数における一時変数の扱いを調整。src/cmd/gc/walk.c
: 型変換(convT2E
/convT2I
)や複合リテラル生成時の一時変数管理を更新。test/live.go
: 一時変数のライブネス解析の改善を検証するための新しいテストケースを追加。
コミット
commit 96d90d0981fd37e16be5d124d39a14cbbd6cde7f
Author: Russ Cox <rsc@golang.org>
Date: Wed Apr 2 14:09:42 2014 -0400
cmd/gc: shorten even more temporary lifetimes
1. Use n->alloc, not n->left, to hold the allocated temp being
passed from orderstmt/orderexpr to walk.
2. Treat method values the same as closures.
3. Use killed temporary for composite literal passed to
non-escaping function argument.
4. Clean temporaries promptly in if and for statements.
5. Clean temporaries promptly in select statements.
As part of this, move all the temporary-generating logic
out of select.c into order.c, so that the temporaries can
be reclaimed.
With the new temporaries, can re-enable the 1-entry
select optimization. Fixes issue 7672.
While we're here, fix a 1-line bug in select processing
turned up by the new liveness test (but unrelated; select.c:72).
Fixes #7686.
6. Clean temporaries (but not particularly promptly) in switch
and range statements.
7. Clean temporary used during convT2E/convT2I.
8. Clean temporaries promptly during && and || expressions.
---
CL 81940043 reduced the number of ambiguously live temps
in the godoc binary from 860 to 711.
CL 83090046 reduced the number from 711 to 121.
This CL reduces the number from 121 to 23.
15 the 23 that remain are in fact ambiguously live.
The final 8 could be fixed but are not trivial and
not common enough to warrant work at this point
in the release cycle.
These numbers only count ambiguously live temps,
not ambiguously live user-declared variables.
There are 18 such variables in the godoc binary after this CL,
so a total of 41 ambiguously live temps or user-declared
variables.
The net effect is that zeroing anything on entry to a function
should now be a rare event, whereas earlier it was the
common case.
This is good enough for Go 1.3, and probably good
enough for future releases too.
Fixes #7345.
LGTM=khr
R=khr
CC=golang-codereviews
https://golang.org/cl/83000048
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/96d90d0981fd37e16be5d124d39a14cbbd6cde7f
元コミット内容
commit 96d90d0981fd37e16be5d124d39a14cbbd6cde7f
Author: Russ Cox <rsc@golang.org>
Date: Wed Apr 2 14:09:42 2014 -0400
cmd/gc: shorten even more temporary lifetimes
1. Use n->alloc, not n->left, to hold the allocated temp being
passed from orderstmt/orderexpr to walk.
2. Treat method values the same as closures.
3. Use killed temporary for composite literal passed to
non-escaping function argument.
4. Clean temporaries promptly in if and for statements.
5. Clean temporaries promptly in select statements.
As part of this, move all the temporary-generating logic
out of select.c into order.c, so that the temporaries can
be reclaimed.
With the new temporaries, can re-enable the 1-entry
select optimization. Fixes issue 7672.
While we're here, fix a 1-line bug in select processing
turned up by the new liveness test (but unrelated; select.c:72).
Fixes #7686.
6. Clean temporaries (but not particularly promptly) in switch
and range statements.
7. Clean temporary used during convT2E/convT2I.
8. Clean temporaries promptly during && and || expressions.
---
CL 81940043 reduced the number of ambiguously live temps
in the godoc binary from 860 to 711.
CL 83090046 reduced the number from 711 to 121.
This CL reduces the number from 121 to 23.
15 the 23 that remain are in fact ambiguously live.
The final 8 could be fixed but are not trivial and
not common enough to warrant work at this point
in the release cycle.
These numbers only count ambiguously live temps,
not ambiguously live user-declared variables.
There are 18 such variables in the godoc binary after this CL,
so a total of 41 ambiguously live temps or user-declared
variables.
The net effect is that zeroing anything on entry to a function
should now be a rare event, whereas earlier it was the
common case.
This is good enough for Go 1.3, and probably good
enough for future releases too.
Fixes #7345.
LGTM=khr
R=khr
CC=golang-codereviews
https://golang.org/cl/83000048
変更の背景
このコミットの主な背景は、Goコンパイラが生成する一時変数(temporary variables)のライフタイムを最適化し、ガベージコレクション(GC)の効率を向上させることにあります。特に、Go 1.3リリースでは、GCの精度とパフォーマンスの改善が重要な目標とされていました。
GoのGCは、変数が「ライブ」(プログラムの実行中にその値が将来使用される可能性がある状態)であるかどうかを判断することで、不要になったメモリを解放します。しかし、コンパイラが一時変数の正確なライブネスを判断できない場合、その変数は「曖昧にライブ」(ambiguously live)と見なされます。このような曖昧な状態の一時変数は、実際には不要になった後もメモリ上に残り続ける可能性があり、GCの効率を低下させます。特に、ポインタを含む可能性のある一時変数が曖昧にライブである場合、関数エントリ時にそのメモリ領域をゼロ初期化する必要が生じ、これがパフォーマンスのオーバーヘッドとなります。
このコミット以前にも、同様の最適化が行われていました。コミットメッセージに記載されているように、以前の変更(CL 81940043とCL 83090046)によって、godoc
バイナリにおける曖昧にライブな一時変数の数が860から121にまで削減されていました。このコミットは、その取り組みをさらに進め、数を121からわずか23にまで劇的に削減することを目指しています。
この最適化の最終的な目標は、「関数エントリ時のゼロ初期化が稀なイベントになる」ことです。これにより、GCのオーバーヘッドが減少し、Goプログラム全体のパフォーマンスが向上します。Go 1.3のリリース目標に照らして、この改善は「十分良い」と判断されています。
前提知識の解説
Goコンパイラ (cmd/gc
)
cmd/gc
はGo言語の公式コンパイラであり、Goソースコードを機械語に変換する役割を担っています。コンパイルプロセスには、構文解析、型チェック、中間表現の生成、最適化、コード生成などが含まれます。このコミットは、主に中間表現の最適化段階、特に一時変数の管理とライブネス解析に関連する部分に焦点を当てています。
一時変数 (Temporary Variables)
一時変数は、コンパイラがプログラムの実行中に内部的に使用するために生成する変数です。これらはソースコードに直接記述されるものではなく、例えば、複雑な式の評価の中間結果、関数呼び出しの引数を準備するための領域、select
文やrange
文のような制御構造の内部処理などに用いられます。一時変数は通常、その使用が終わるとすぐに解放されるべきですが、コンパイラのライブネス解析が不十分だと、必要以上に長くメモリに保持されてしまうことがあります。
ライブネス解析 (Liveness Analysis)
ライブネス解析は、コンパイラのデータフロー解析の一種で、プログラムの特定のポイントにおいて、ある変数の値が将来の計算で利用される可能性があるかどうか(すなわち「ライブ」であるか)を判断します。変数がライブでなくなった場合、その変数が占めていたメモリは再利用可能になります。
曖昧にライブな一時変数 (Ambiguously Live Temporaries)
これは、コンパイラがその正確なライブネスを判断できない一時変数を指す、Goコンパイラ内部の概念です。コンパイラが変数のライブネスを確実に判断できない場合、安全のためにその変数を「ライブである」と仮定し、メモリを解放せずに保持し続けます。特にポインタを含む一時変数が曖昧にライブであると、ガベージコレクタが誤って古いポインタを追跡したり、メモリリークを引き起こしたりするリスクがあるため、関数エントリ時にそのメモリ領域をゼロで初期化する(ゼロイング)必要が生じます。このゼロイングはパフォーマンスのオーバーヘッドとなります。このコミットは、この「曖昧さ」を減らすことで、ゼロイングの必要性を減らすことを目指しています。
エスケープ解析 (Escape Analysis)
エスケープ解析は、変数がスタックに割り当てられるべきか、それともヒープに割り当てられるべきかを決定するコンパイラ最適化です。変数が関数スコープを超えて「エスケープ」する場合(例:ポインタが返される、グローバル変数に代入されるなど)、その変数はヒープに割り当てられます。エスケープしない変数はスタックに割り当てられ、関数が終了すると自動的に解放されるため、GCの負担が軽減されます。このコミットは、一時変数が「非エスケープ」である場合に、より積極的にそのライフタイムを管理することを目指しています。
order.c
, select.c
, walk.c
これらはGoコンパイラ(cmd/gc
)の主要なソースファイルの一部です。
order.c
: 式や文の評価順序を決定し、必要に応じて一時変数を導入する役割を担います。このコミットでは、一時変数のクリーンアップロジックの多くがこのファイルに集約されています。select.c
: Goのselect
文のコンパイルロジックを扱います。このコミットでは、一時変数管理の一部がorder.c
に移動されました。walk.c
: 中間表現ツリーを走査し、型チェック後の最終的なコード生成に近い変換を行います。
OVARKILL
OVARKILL
は、Goコンパイラの中間表現におけるノードタイプの一つで、特定の変数がその時点で「死んだ」(ライブでなくなった)ことを示すマーカーです。このマーカーが挿入されることで、コンパイラは変数のメモリをより早く再利用できる可能性を認識します。
n->left
vs n->alloc
Goコンパイラの内部では、抽象構文木(AST)のノード(Node
構造体)がプログラムの要素を表します。以前は、一時変数を保持するためにn->left
フィールドが汎用的に使われることがありましたが、このコミットでは、一時変数の割り当て専用のn->alloc
フィールドを導入し、より明確なセマンティクスと管理を可能にしています。
convT2E
, convT2I
これらはGoコンパイラが内部的に使用する型変換操作です。
convT2E
(Convert Type to Interface): 具体型からインターフェース型への変換。convT2I
(Convert Type to Interface): 具体型からインターフェース型への変換(convT2E
と似ているが、文脈が異なる場合がある)。 これらの変換では、一時的な値が生成されることがあり、その一時変数のライフタイム管理が重要になります。
Goのselect
文、if
文、for
文、&&
/||
演算子のセマンティクス
これらのGoの制御構造や演算子は、それぞれ特定の評価順序と条件分岐ロジックを持ちます。例えば、if
文や&&
/||
演算子では、条件式の評価結果によって後続のコードが実行されるかどうかが決まります。select
文では、複数のチャネル操作のうち一つだけが実行されます。これらの構造の内部で生成される一時変数は、実行パスに応じて異なるタイミングで不要になるため、そのライフタイムを正確に管理することがGC効率に直結します。
技術的詳細
このコミットは、Goコンパイラが生成する一時変数のライフタイムを短縮するための多岐にわたる改善を含んでいます。以下に、コミットメッセージに記載された各ポイントの詳細を解説します。
-
n->alloc
の使用:- 以前は、
orderstmt
/orderexpr
からwalk
フェーズに渡される割り当て済み一時変数を保持するために、汎用的なn->left
フィールドが使用されていました。 - この変更により、一時変数の割り当て専用の
n->alloc
フィールドが導入され、n->left
の代わりにこれを使用するようになりました。これにより、コードの意図が明確になり、一時変数の管理がより構造化されます。closure.c
、range.c
、sinit.c
、walk.c
でこの変更が適用されています。
- 以前は、
-
メソッド値をクロージャと同様に扱う:
- メソッド値(例:
t.Inc
のような部分適用された関数)は、コンパイラ内部でクロージャと類似の構造として扱われるようになりました。これにより、クロージャに適用される一時変数のライフタイム最適化がメソッド値にも適用され、より効率的なメモリ管理が可能になります。closure.c
でwalkpartialcall
のロジックが更新されています。
- メソッド値(例:
-
非エスケープ関数引数に渡される複合リテラルの一時変数の解放:
- 配列リテラル、ポインタリテラル、構造体リテラルなどの複合リテラルが、ヒープにエスケープしない関数引数として渡される場合、その生成に使用された一時変数が、関数呼び出しの完了後すぐに解放されるようになりました。
src/cmd/gc/esc.c
のesccall
関数において、OCALLPART
、OCLOSURE
、ODDDARG
に加えて、OARRAYLIT
、OPTRLIT
、OSTRUCTLIT
がnoescape
としてマークされるようになりました。これにより、これらの複合リテラルが非エスケープであることがコンパイラに伝わり、一時変数の早期解放が可能になります。
-
if
およびfor
文における一時変数の即時クリーンアップ:- 以前は、
if
やfor
文の条件式で生成された一時変数が、文全体の終了までライブのまま残ってしまう問題がありました。 - このコミットでは、
order.c
において、if
文の各ブランチ(then
とelse
)の開始時、およびfor
文のループボディの開始時に、条件式で生成された一時変数を積極的にクリーンアップするロジックが導入されました。これは、cleantempnopop
関数とcleantemp
関数を用いて実現されています。これにより、一時変数のライフタイムが大幅に短縮されます。
- 以前は、
-
select
文における一時変数の即時クリーンアップ:select
文は複数のチャネル操作を扱うため、一時変数の管理が複雑でした。このコミットでは、select
文の各case
ブロックの開始時に、そのcase
に関連する一時変数をクリーンアップするようになりました。- この変更の重要な点として、
select
文の一時変数生成ロジックの多くがselect.c
からorder.c
に移動されました。これにより、order.c
の汎用的な一時変数管理メカニズムを利用して、select
文の一時変数をより効率的に解放できるようになりました。 - この改善により、以前は無効化されていた1エントリの
select
最適化(select
文にdefault
がなく、case
が一つしかない場合に、select
を通常のチャネル操作に変換する最適化)が再有効化されました。これはIssue 7672を修正します。 - また、
select.c
の行72にあった1行のバグも修正されました(Issue 7686)。これは新しいライブネス解析テストによって発見されたもので、一時変数管理とは直接関係ないものの、このコミットで修正されました。
-
switch
およびrange
文における一時変数のクリーンアップ:if
やfor
、select
ほど積極的ではありませんが、switch
文とrange
文においても一時変数のクリーンアップが改善されました。switch
文では、文の終了時に一時変数をクリーンアップするようになりました。コミットメッセージでは、switch
文がバイナリサーチに書き換えられる可能性があるため、より積極的なクリーンアップは複雑であると述べられています。range
文では、イテレータ用の一時変数の管理が改善されています。
-
convT2E
/convT2I
における一時変数のクリーンアップ:- 具体型からインターフェース型への変換(
convT2E
/convT2I
)の際に生成される一時変数が、変換後すぐにクリーンアップされるようになりました。 order.c
のorderexpr
関数において、OCONVIFACE
(インターフェース変換)の場合に、引数がアドレス指定可能(addressable)な一時変数になるようにorderaddrtemp
が呼び出されています。これにより、ランタイムへの引数渡しが適切に行われ、一時変数のライフタイムが短縮されます。
- 具体型からインターフェース型への変換(
-
&&
および||
式における一時変数の即時クリーンアップ:- 論理AND(
&&
)および論理OR(||
)演算子は、ショートサーキット評価を行います。つまり、左側のオペランドの結果によって右側のオペランドが評価されない場合があります。 - このコミットでは、
order.c
のorderexpr
関数において、&&
や||
の左側のオペランドで生成された一時変数が、右側のオペランドの評価が始まる前にクリーンアップされるようになりました。これにより、ショートサーキットが発生した場合でも、不要な一時変数が長く残り続けることがなくなります。
- 論理AND(
これらの変更は、godoc
バイナリにおける曖昧にライブな一時変数の数を121から23にまで削減するという顕著な効果をもたらしました。これにより、関数エントリ時のゼロ初期化の必要性が大幅に減少し、Go 1.3のGCパフォーマンス目標達成に大きく貢献しています。
コアとなるコードの変更箇所
このコミットのコアとなる変更は、src/cmd/gc/order.c
における一時変数のクリーンアップロジックの導入と、既存の制御構造へのその適用です。
一時変数クリーンアップ関数の導入
// src/cmd/gc/order.c
// ...
// Cleantempnopop emits to *out VARKILL instructions for each temporary
// above the mark on the temporary stack, but it does not pop them
// from the stack.
static void
cleantempnopop(NodeList *mark, Order *order, NodeList **out)
{
NodeList *l;
Node *kill;
for(l=order->temp; l != mark; l=l->next) {
kill = nod(OVARKILL, l->n, N);
typecheck(&kill, Etop);
*out = list(*out, kill);
}
}
// ...
static void
cleantemp(NodeList *top, Order *order)
{
cleantempnopop(top, order, &order->out);
poptemp(top, order);
}
cleantempnopop
は、指定されたマークより上の一時変数スタックにある各一時変数に対してOVARKILL
命令を生成し、指定された出力リスト(*out
)に追加します。cleantemp
は、cleantempnopop
を呼び出した後、一時変数スタックからそれらの変数をポップします。
if
文における一時変数クリーンアップの適用
// src/cmd/gc/order.c
// ...
case OIF:
// Clean temporaries from condition at
// beginning of both branches.
t = marktemp(order);
orderexprinplace(&n->ntest, order);
l = nil;
cleantempnopop(t, order, &l);
n->nbody = concat(l, n->nbody); // then ブランチの先頭に VARKILL を挿入
l = nil;
cleantempnopop(t, order, &l);
n->nelse = concat(l, n->nelse); // else ブランチの先頭に VARKILL を挿入
poptemp(t, order);
orderblock(&n->nbody);
orderblock(&n->nelse);
order->out = list(order->out, n);
break;
// ...
OIF
(if
文)の処理では、条件式(n->ntest
)の評価後に一時変数のマーク(t
)を設定します。そして、then
ブランチ(n->nbody
)とelse
ブランチ(n->nelse
)のそれぞれに、条件式で生成された一時変数をクリーンアップするOVARKILL
命令を挿入しています。これにより、どちらのパスが実行されても、条件式の一時変数がすぐに解放されるようになります。
select
文における一時変数クリーンアップの適用とロジックの移動
select
文の処理はsrc/cmd/gc/select.c
からsrc/cmd/gc/order.c
に一時変数生成ロジックが移動され、より複雑な変更が行われています。
// src/cmd/gc/order.c
// ...
case OSELECT:
// Special: clean case temporaries in each block entry.
// Select must enter one of its blocks, so there is no
// need for a cleaning at the end.
t = marktemp(order);
for(l=n->list; l; l=l->next) {
// ... 各 case のチャネル操作の順序付けと一時変数生成 ...
// 例: OSELRECV (<-c) の場合
// orderexpr(&r->right->left, order); // チャネル式の順序付け
// ... 一時変数の割り当てと OAS ノードの生成 ...
// l->n->ninit = list(l->n->ninit, tmp2); // ninit に一時変数への代入を追加
// orderblock(&l->n->ninit); // ninit の順序付け
}
// Now that we have accumulated all the temporaries, clean them.
// Also insert any ninit queued during the previous loop.
for(l=n->list; l; l=l->next) {
cleantempnopop(t, order, &l->n->ninit); // 各 case の ninit に VARKILL を挿入
l->n->nbody = concat(l->n->ninit, l->n->nbody); // ninit を body の先頭に結合
l->n->ninit = nil;
}
order->out = list(order->out, n);
poptemp(t, order);
break;
// ...
select
文では、まず全体の一時変数マークを設定します。次に、各case
のチャネル操作(送受信など)を順序付けし、必要に応じて一時変数を導入します。重要なのは、ループの最後にcleantempnopop
を呼び出し、各case
のninit
リスト(そのcase
ブロックの先頭で実行される初期化文のリスト)に、select
文全体で生成された一時変数をクリーンアップするOVARKILL
命令を挿入している点です。これにより、どのcase
が選択されても、そのcase
ブロックの実行開始時に不要な一時変数が解放されます。
&&
および||
式における一時変数クリーンアップの適用
// src/cmd/gc/order.c
// ...
case OANDAND:
case OOROR:
mark = marktemp(order);
orderexpr(&n->left, order); // 左オペランドの順序付け
// Clean temporaries from first branch at beginning of second.
// Leave them on the stack so that they can be killed in the outer
// context in case the short circuit is taken.
l = nil;
cleantempnopop(mark, order, &l);
n->right->ninit = concat(l, n->right->ninit); // 右オペランドの ninit に VARKILL を挿入
orderexprinplace(&n->right, order); // 右オペランドの順序付け
break;
// ...
OANDAND
(&&
)とOOROR
(||
)の処理では、左オペランドの評価後に一時変数のマークを設定します。そして、右オペランドのninit
リストに、左オペランドで生成された一時変数をクリーンアップするOVARKILL
命令を挿入します。これにより、ショートサーキットが発生して右オペランドが評価されない場合でも、左オペランドの一時変数は外側のコンテキストで適切に解放されるようになります。
コアとなるコードの解説
これらのコアとなるコード変更は、Goコンパイラが一時変数のライフタイムをより正確に、そしてより積極的に管理するための根本的なアプローチを示しています。
-
cleantempnopop
とcleantemp
の導入:- これらの関数は、一時変数のクリーンアップロジックをカプセル化し、再利用可能にすることで、コンパイラ全体で一貫した一時変数管理を可能にしました。
- 特に
cleantempnopop
は、OVARKILL
命令を生成するだけで一時変数スタックからポップしないため、複数の実行パス(例:if
のthen
とelse
、select
の各case
)で同じ一時変数をクリーンアップする命令を挿入しつつ、その一時変数が外側のスコープでまだライブである可能性がある場合に備えることができます。
-
制御構造への積極的な適用:
if
、for
、select
、&&
、||
といった制御構造は、プログラムの実行フローを分岐させます。以前は、これらの分岐の内部で生成された一時変数が、分岐が終了するまで(あるいは関数が終了するまで)ライブのまま残ってしまうことがありました。- このコミットでは、各分岐の開始点や、論理演算子のショートサーキットの分岐点に
OVARKILL
命令を挿入することで、一時変数が不要になった瞬間に即座に「死んだ」とマークされるようにしました。これにより、一時変数のライブ期間が最小限に抑えられ、ガベージコレクタがより早くメモリを再利用できるようになります。 - 特に
select
文のロジックをorder.c
に移動したことは、select
の複雑なセマンティクスと一時変数管理を、コンパイラの汎用的な順序付け・一時変数管理フレームワークに統合した点で重要です。これにより、select
文の最適化(1エントリのselect
最適化の再有効化など)も可能になりました。
-
n->alloc
への移行:- 一時変数の割り当てに専用の
n->alloc
フィールドを使用することで、コンパイラの内部表現がより明確になり、一時変数のライフタイム管理ロジックがより堅牢になりました。これは、コンパイラの保守性と拡張性にも寄与します。
- 一時変数の割り当てに専用の
これらの変更は、Goコンパイラが生成するコードの効率を向上させ、特にガベージコレクションのパフォーマンスに直接的な良い影響を与えます。一時変数のライフタイムを短縮することで、GCがスキャンする必要のあるメモリ領域が減り、結果としてGCの一時停止時間(pause time)の削減にも貢献します。
関連リンク
- Go CL 83000048: https://golang.org/cl/83000048
- Go Issue 7672: (このIssueは公式のGitHubリポジトリでは見つかりませんでしたが、コミットメッセージによると1エントリの
select
最適化の再有効化に関連しています。) - Go Issue 7686: (このIssueも公式のGitHubリポジトリでは見つかりませんでしたが、コミットメッセージによると
select.c:72
のバグ修正に関連しています。) - Go Issue 7345: (このIssueも公式のGitHubリポジトリでは見つかりませんでしたが、コミットメッセージによると一時変数のライフタイムに関する一般的な問題に関連しています。)
参考にした情報源リンク
- Go 1.3 Release Notes - Runtime and garbage collection: https://go.dev/doc/go1.3#runtime
- Go 1.3 Release Notes - Compiler: https://go.dev/doc/go1.3#compiler
- Go Escape Analysis: https://dev.to/aureliev/go-escape-analysis-101-3g0j
- Go Escape Analysis (another source): https://kelche.co/blog/go-escape-analysis/
- Go Garbage Collection (general overview): https://go.dev/doc/gc-guide
- Red Hat Security Advisory RHSA-2023:7672 (Note: This was a search result for "Go issue 7672" but is unrelated to the commit's technical content): https://access.redhat.com/errata/RHSA-2023:7672
- CVE-2025-7345 (Note: This was a search result for "Go issue 7345" but is unrelated to the commit's technical content): https://nvd.nist.gov/vuln/detail/CVE-2025-7345