Goでの構造体のスタックとヒープの割り当て、およびガベージコレクションとの関係

ジョー:

私はGoを始めたばかりで、自動変数がスタックに存在し、割り当てられたメモリがヒープに存在するCスタイルのスタックベースのプログラミングと、Pythonスタイルのスタックベースのプログラミングが、スタック上に存在するものだけが、ヒープ上のオブジェクトへの参照/ポインターです。

私の知る限り、次の2つの関数は同じ出力を提供します。

func myFunction() (*MyStructType, error) {
    var chunk *MyStructType = new(HeaderChunk)

    ...

    return chunk, nil
}


func myFunction() (*MyStructType, error) {
    var chunk MyStructType

    ...

    return &chunk, nil
}

つまり、新しい構造体を割り当ててそれを返します。

それをCで書いた場合、最初のオブジェクトはヒープにオブジェクトを置き、2番目のオブジェクトはスタックにオブジェクトを置きます。1つ目はヒープへのポインターを返し、2つ目はスタックへのポインターを返します。これは、関数が戻ったときまでに蒸発していました。これは悪いことです。

Python(またはC#を除く他の多くの現代言語)で記述した場合、例2は不可能でした。

Goガベージは両方の値を収集するので、上記の両方の形式で問題ありません。

引用するには:

Cとは異なり、ローカル変数のアドレスを返すことはまったく問題ありません。変数に関連付けられたストレージは、関数が戻った後も存続します。実際、複合リテラルのアドレスを取得すると、評価されるたびに新しいインスタンスが割り当てられるため、これらの最後の2行を組み合わせることができます。

http://golang.org/doc/effective_go.html#functions

しかし、それはいくつかの質問を提起します。

1-例1では、構造体はヒープで宣言されています。例2はどうですか?それはCの場合と同じようにスタックで宣言されていますか、それともヒープに移動しますか?

2-例2がスタックで宣言されている場合、関数が戻った後、例2はどのように利用できるままですか

3-例2が実際にヒープで宣言されている場合、構造体は参照ではなく値で渡されるのはなぜですか。この場合のポインタのポイントは何ですか?

ソニア:

「スタック」と「ヒープ」という言葉が言語仕様のどこにも現れていないことは注目に値します。あなたの質問は「...はスタックで宣言されています」、「...はヒープで宣言されています」という言葉で書かれていますが、Go宣言の構文はスタックやヒープについて何も述べていないことに注意してください。

それは技術的にあなたのすべての質問への答えを実装依存にします。もちろん、実際には(goroutineごとに)スタックとヒープがあり、スタック上にあるものとヒープ上にあるものがあります。コンパイラーは厳格なルール(「new常にヒープに割り当てる」など)に従う場合と、オブジェクトがスタックに存在できるかどうか、またはヒープに割り当てる必要があるかどうかを判断するために「エスケープ分析」を行う場合があります。

例2では、​​エスケープ分析は、エスケープする構造体へのポインタを示すため、コンパイラは構造体を割り当てる必要があります。この場合、Goの現在の実装は厳密な規則に従っていると思います。つまり、アドレスが構造体のいずれかの部分から取得された場合、構造体はヒープ上に置かれます。

質問3では、用語について混乱する恐れがあります。Goのすべては値で渡され、参照渡しはありません。ここでは、ポインタ値を返しています。ポインタのポイントは何ですか?次の例の変更を検討してください。

type MyStructType struct{}

func myFunction1() (*MyStructType, error) {
    var chunk *MyStructType = new(MyStructType)
    // ...
    return chunk, nil
}

func myFunction2() (MyStructType, error) {
    var chunk MyStructType
    // ...
    return chunk, nil
}

type bigStruct struct {
    lots [1e6]float64
}

func myFunction3() (bigStruct, error) {
    var chunk bigStruct
    // ...
    return chunk, nil
}

myFunction2を変更して、構造体のアドレスではなく構造体を返すようにしました。ここで、myFunction1とmyFunction2のアセンブリ出力を比較します。

--- prog list "myFunction1" ---
0000 (s.go:5) TEXT    myFunction1+0(SB),$16-24
0001 (s.go:6) MOVQ    $type."".MyStructType+0(SB),(SP)
0002 (s.go:6) CALL    ,runtime.new+0(SB)
0003 (s.go:6) MOVQ    8(SP),AX
0004 (s.go:8) MOVQ    AX,.noname+0(FP)
0005 (s.go:8) MOVQ    $0,.noname+8(FP)
0006 (s.go:8) MOVQ    $0,.noname+16(FP)
0007 (s.go:8) RET     ,

--- prog list "myFunction2" ---
0008 (s.go:11) TEXT    myFunction2+0(SB),$0-16
0009 (s.go:12) LEAQ    chunk+0(SP),DI
0010 (s.go:12) MOVQ    $0,AX
0011 (s.go:14) LEAQ    .noname+0(FP),BX
0012 (s.go:14) LEAQ    chunk+0(SP),BX
0013 (s.go:14) MOVQ    $0,.noname+0(FP)
0014 (s.go:14) MOVQ    $0,.noname+8(FP)
0015 (s.go:14) RET     ,

ここでmyFunction1の出力がpeterSOの(優れた)回答とは異なることを心配しないでください。明らかに異なるコンパイラを実行しています。それ以外の場合は、* myStructTypeではなくmyStructTypeを返すようにmyFunction2を変更したことを確認してください。runtime.newの呼び出しはなくなりました。これは、場合によっては良いことです。ちょっと待って、これがmyFunction3です。

--- prog list "myFunction3" ---
0016 (s.go:21) TEXT    myFunction3+0(SB),$8000000-8000016
0017 (s.go:22) LEAQ    chunk+-8000000(SP),DI
0018 (s.go:22) MOVQ    $0,AX
0019 (s.go:22) MOVQ    $1000000,CX
0020 (s.go:22) REP     ,
0021 (s.go:22) STOSQ   ,
0022 (s.go:24) LEAQ    chunk+-8000000(SP),SI
0023 (s.go:24) LEAQ    .noname+0(FP),DI
0024 (s.go:24) MOVQ    $1000000,CX
0025 (s.go:24) REP     ,
0026 (s.go:24) MOVSQ   ,
0027 (s.go:24) MOVQ    $0,.noname+8000000(FP)
0028 (s.go:24) MOVQ    $0,.noname+8000008(FP)
0029 (s.go:24) RET     ,

それでもruntime.newへの呼び出しはなく、はい、実際には値によって8MBのオブジェクトを返すように機能します。それは機能しますが、通常はしたくありません。ここでのポインターのポイントは、8MBのオブジェクトをプッシュしないようにすることです。

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

プログラムのメモリ割り当てによると、列挙型、構造体、共用体、クラス、インターフェイス、およびそれらの間の関係の違いは何ですか

分類Dev

Javaでのガベージコレクションの理解、およびヒープスペースの誤用を防ぐ方法

分類Dev

ダイナミックメモリの割り当て解除におけるフルガベージコレクションとはどういう意味ですか?

分類Dev

使用後のガベージコレクション宣言構造体

分類Dev

構造マップ-コンストラクターの依存関係のコレクション

分類Dev

Juliaのメモリ割り当てとガベージコレクションで混乱

分類Dev

構造体および構造体のコレクションに揮発性

分類Dev

双方向関係のガベージコレクション

分類Dev

Goでのガベージコレクションとポインターの正しい使用法

分類Dev

Golangマップと構造体およびJSONでのインターフェースの使用

分類Dev

再帰関数でのヒープへの割り当てとスタックへの割り当て

分類Dev

Javaはオブジェクトの割り当て解除とガベージコレクションの後もシステムメモリを使用します

分類Dev

ガベージコレクタは、それが必要として、Androidのアプリケーションで「メモリスラッシュ」解放ません

分類Dev

クレートデータベース-シャードとパーティションおよびノード間の関係

分類Dev

構造体のメモリ割り当てとコピーコンストラクタ

分類Dev

ジュリアのccall割り当てデータのガベージコレクション

分類Dev

Haskellでの反復とガベージコレクション

分類Dev

Haskellでの反復とガベージコレクション

分類Dev

PythonでのMemoryViewsとガベージコレクション

分類Dev

単純な割り当て中のガベージコレクション

分類Dev

ヒープ上のスタッククラスの構造体

分類Dev

構造体を別の構造体に割り当てると、ガベージが発生します

分類Dev

データ/ bss /ヒープおよびスタックでのメモリ割り当て

分類Dev

C ++クラスメンバー:スタックとヒープの割り当て

分類Dev

構造体およびオブザーバーパターンとのメモリアクセスの競合

分類Dev

サブクラス内の構造体、selfに割り当てるときにオプションでアンラップ

分類Dev

リクエストおよびガベージコレクション中のWCF非同期

分類Dev

クラスメンバー関数の戻り型をプライベート構造体のオブジェクトとして設定する方法

分類Dev

SWIGのガベージコレクションとカスタムゲッター

Related 関連記事

  1. 1

    プログラムのメモリ割り当てによると、列挙型、構造体、共用体、クラス、インターフェイス、およびそれらの間の関係の違いは何ですか

  2. 2

    Javaでのガベージコレクションの理解、およびヒープスペースの誤用を防ぐ方法

  3. 3

    ダイナミックメモリの割り当て解除におけるフルガベージコレクションとはどういう意味ですか?

  4. 4

    使用後のガベージコレクション宣言構造体

  5. 5

    構造マップ-コンストラクターの依存関係のコレクション

  6. 6

    Juliaのメモリ割り当てとガベージコレクションで混乱

  7. 7

    構造体および構造体のコレクションに揮発性

  8. 8

    双方向関係のガベージコレクション

  9. 9

    Goでのガベージコレクションとポインターの正しい使用法

  10. 10

    Golangマップと構造体およびJSONでのインターフェースの使用

  11. 11

    再帰関数でのヒープへの割り当てとスタックへの割り当て

  12. 12

    Javaはオブジェクトの割り当て解除とガベージコレクションの後もシステムメモリを使用します

  13. 13

    ガベージコレクタは、それが必要として、Androidのアプリケーションで「メモリスラッシュ」解放ません

  14. 14

    クレートデータベース-シャードとパーティションおよびノード間の関係

  15. 15

    構造体のメモリ割り当てとコピーコンストラクタ

  16. 16

    ジュリアのccall割り当てデータのガベージコレクション

  17. 17

    Haskellでの反復とガベージコレクション

  18. 18

    Haskellでの反復とガベージコレクション

  19. 19

    PythonでのMemoryViewsとガベージコレクション

  20. 20

    単純な割り当て中のガベージコレクション

  21. 21

    ヒープ上のスタッククラスの構造体

  22. 22

    構造体を別の構造体に割り当てると、ガベージが発生します

  23. 23

    データ/ bss /ヒープおよびスタックでのメモリ割り当て

  24. 24

    C ++クラスメンバー:スタックとヒープの割り当て

  25. 25

    構造体およびオブザーバーパターンとのメモリアクセスの競合

  26. 26

    サブクラス内の構造体、selfに割り当てるときにオプションでアンラップ

  27. 27

    リクエストおよびガベージコレクション中のWCF非同期

  28. 28

    クラスメンバー関数の戻り型をプライベート構造体のオブジェクトとして設定する方法

  29. 29

    SWIGのガベージコレクションとカスタムゲッター

ホットタグ

アーカイブ