2017-03-20 19 views
1

アドレスを取得し、Goの関数内のローカル変数へのポインタを返すと、コンパイラはスタックではなくヒープに割り当てるため、返されたポインタは有効なままです。Goで構造体メンバまたは埋め込み構造体にポインタを戻していますか?

ここで、構造体メンバーまたは埋め込み構造体のアドレスを取得して返すとどうなりますか?

type A struct { 
    a,b,c int 
} 
type B struct { 
    A 
    d,e,f int 
} 
func (b *B) get1() *A { 
    return &b.A 
} 
func (b *B) get2() *A { 
    localB := B{} 
    return &localB.A 
} 

コンパイラはヒープに組み込みの構造体Aを割り当て、Bのメンバーをスタックに保持しますか?

localB.A参照がまだ使用されていても、ガベージコレクタはlocalBを収集しますか?

リフレクションによってアクセスされた場合、スタックまたはヒープに埋め込み構造体を保持する方法をコンパイラが決定する方法を教えてください。

+0

こちらは安全です。あなたは単に**ダングリングポインタを生成することはできません。あなたが何をするかは問題ではありません(あなたが安全でないパッケージから離れている場合)。コンパイラはここで安全に動作しています。スタック上の割り当てが安全であることが証明できない場合は、ヒープに割り当てられます。何も心配する必要はありません。一緒に移動。 – Volker

+0

@Volker私は指をぶらつくことを心配していませんが、私はすぐにガベージコレクションされていない構造を囲むことについて心配しています。 – alpav

+0

最初に:タイプAは空であり、あなたの例では何も収集されません。 GCがlocalB.Aが使用されている場合、localBをどのように集めることができるのかより、実際にはAが空ではないと仮定しますか?あなたはGCが壊れていると仮定していますか? – Volker

答えて

2

コンパイラは、escape analysisを実行して、変数が作成されたスコープ外で使用できるかどうかを判断します。その場合は、ヒープに割り当てる必要があります。コンパイラは、これが起こらないことを確認できる場合、変数をスタックに割り当てます。

しかし、これはコンパイラの現在の動作ですが、仕様には記載されていないため、今後のバージョンで変更される可能性があります。

3

なぜこれらの詳細について疑問に思っていますか? Go FAQ(強調鉱山)を引用

:正しさの観点から

、あなたが知っている必要はありません。 Goの各変数 は、参照がある限り存在します。実装によって選択されたストレージ の場所は、言語の意味 とは無関係です。現在のコンパイラで

、変数は 変数がヒープ上に割り当ての候補であることに注意そのアドレスを持っている場合。しかし、基本的な エスケープ解析では、その変数が関数からの復帰を過ぎて生き残らず、スタックに常駐できるような変数がある場合を認識します。

コンパイラとガベージコレクタの動作は、実装によって異なり、リリースによって変更される場合があります。 openingステートメントが常にtrueであることをイベントで証明することはできません。コンパイラは、関数の記述方法または呼び出し方法に応じて、さらに最適化を適用することがあります。