KDOC 416: Goのエスケープ解析における2つの不変条件を見る

この文書のステータス

  • 作成
    • 2025-07-20 貴島
  • レビュー
    • 2025-07-24 貴島

概要

Goのドキュメントにヒープエスケープの「不変条件」が書かれていたので、見る。

// Escape analysis.
//
// Here we analyze functions to determine which Go variables
// (including implicit allocations such as calls to "new" or "make",
// composite literals, etc.) can be allocated on the stack. The two
// key invariants we have to ensure are: (1) pointers to stack objects
// cannot be stored in the heap, and (2) pointers to a stack object
// cannot outlive that object (e.g., because the declaring function
// returned and destroyed the object's stack frame, or its space is
// reused across loop iterations for logically distinct variables).

2つの不変条件。

  • (1)スタックオブジェクトへのポインタはヒープに保存できない
  • (2)スタックオブジェクトへのポインタはそのオブジェクトより長生きできない
    • 関数を抜けるとオブジェクトのスタックフレームは解放される。もしくは解放されたスペースがループ内で論理的に異なる変数として再利用される

つまり、保存場所とポインタ先の関係、スタックオブジェクトとスタックオブジェクトのライフタイムの関係、に関する原則と解釈した。

  • (1) 保存場所とポインタ先の問題(空間)
    • ルール: スタックオブジェクトへのポインタは、ヒープ領域に保存してはならない。
    • 理由: ヒープにあるデータは、関数呼び出しを超えて長生きする可能性がある。しかし、それが指し示す先のスタックオブジェクトは、関数を抜けると解放される。結果、ヒープ上には実体のないポインタ(ダングリングポインタ)が残る
    • 解決策: コンパイラは、ヒープに保存されるポインタが指す先のオブジェクトもヒープにエスケープさせる。これによってヒープからヒープを指す状態にする
  • (2) ポインタ「寿命」の問題(時間)
    • ルール: スタックオブジェクトへのポインタは、そのオブジェクトのライフタイムを超えて存在してはならない
    • 理由: 関数を抜けるとスタックオブジェクトは消える。そのポインタが残るとダングリングポインタとなる
    • 解決策: コンパイラは、ポインタがオブジェクトのライフタイムを超えて使われる可能性を検知したら、そのオブジェクト自体を最初からヒープに確保する

関連