25

ガベージ コレクターを回避/最小化したい場合があるため、その方法を確認したいと思います。

次が正しいと思います。

  • 関数の先頭で変数を宣言します。
  • スライスの代わりに配列を使用するには。

もう?

4

2 に答える 2

37

Go でガベージ コレクションを最小限に抑えるには、ヒープ割り当てを最小限に抑える必要があります。ヒープ割り当てを最小限に抑えるには、いつ割り当てが行われるかを理解する必要があります。

次のことは常に割り当てを引き起こします (少なくとも Go 1 の gc コンパイラでは):

  • new組み込み関数の使用
  • 組み込み関数の使用make(まれなまれなケースを除く)
  • 値の型がスライス、マップ、または&演算子を含む構造体である場合の複合リテラル
  • 機械語よりも大きな値をインターフェースに入れる。(たとえば、文字列、スライス、および一部の構造体は、機械語よりも大きくなります。)
  • string[]byte、および間の変換[]rune
    • Go 1.3 の時点で、コンパイラはこの式を割り当てない特別なケースにしますm[string(b)]。ここmで、 はマップで、b[]byte
  • 非定数整数値をstring
  • deferステートメント
  • goステートメント
  • ローカル変数をキャプチャする関数リテラル

詳細に応じて、次のことが原因で割り当てが発生する可能性があります。

  • 変数のアドレスを取得します。アドレスは暗黙的に取得できることに注意してください。たとえば、ポインタではなく、メソッドにポインタ レシーバ タイプがある場合a.b()のアドレスを取得する場合があります。aab
  • append組み込み関数の使用
  • 可変個引数関数またはメソッドの呼び出し
  • 配列のスライス
  • マップへの要素の追加

リストは完全であることを意図しており、私はそれにかなりの自信を持っていますが、喜んで追加や修正を検討します。

割り当てがどこで行われているかわからない場合は、他の人が提案したようにいつでもプロファイリングするか、コンパイラによって生成されたアセンブリを確認できます。

于 2012-09-05T21:38:10.047 に答える
27

ごみを避けることは比較的簡単です。割り当てが行われている場所を理解し、割り当てを回避できるかどうかを確認する必要があります。

まず、関数の先頭で変数を宣言しても役に立ちません。コンパイラは違いを知りません。しかし、人間はその違いを知り、それが彼らを悩ませます。

スライスの代わりに配列を使用しても機能しますが、これは配列が (逆参照されない限り) スタックに置かれるためです。配列には、関数間で値渡し (コピー) されるという事実など、他の問題があります。関数が戻るときに解放されるため、スタック上のものはすべて「ガベージではありません」。関数をエスケープする可能性のあるポインタまたはスライスは、ガベージ コレクタがある時点で処理する必要があるヒープに置かれます。

あなたができる最善のことは、割り当てを避けることです。不要な大量のデータの処理が完了したら、それらを再利用します。これは、Go ブログのプロファイリング チュートリアルで使用されている方法です。読むことをお勧めします。

プロファイリング チュートリアルの例以外の別の例:[]intという名前の型のスライスがあるとしますxs。条件に達するまで継続的に追加し、[]intそれをリセットして最初からやり直すことができます。実行するxs = nilと、スライスの基になる配列が収集されるガベージとして宣言されます。Append は、次に使用するときに xs を再割り当てします。代わりに を実行xs = xs[:0]すると、まだリセットされますが、古い配列は保持されます。

ほとんどの場合、ガベージの作成を回避しようとするのは時期尚早の最適化です。ほとんどのコードでは問題ありません。しかし、実行されるたびに多くの割り当てを行う関数が何度も呼び出されることがあります。または、再利用する代わりに再割り当てするループ。船外に出る前に、ボトルネックが見えるまで待ちます。

于 2012-09-05T19:18:07.423 に答える