研究ノートに行く(75)-スタックメモリ、ヒープメモリ、エスケープ分析

転送元:https//kaiwu.lagou.com/course/courseInfo.htm?courseId = 536# / detail /
pc?id = 5247

プログラマーがビジネスコードの実装により集中できるようにするために、このGo言語はガベージコレクションメカニズムを追加して、使用されなくなったメモリを自動的に再利用します。Goこの言語には、スタックメモリとヒープメモリの2つのメモリスペースがあります。

1.スタックメモリ

スタックでは、図に示すように、線形テーブルの一方の端にのみデータを配置し、この端でLIFO(後入れ先出し)の順序でデータを取り出すことができます。
スタックメモリ
要素をスタックに配置するプロセスは、プッシュと呼ばれます。スタックを押すと、スタック上の要素の数が増えます。最後に配置された要素は常にスタックの一番上にあり、最初に配置された要素は常にスタックの一番下にあります。

スタックから要素を削除する場合、それらはスタックの最上位からのみ削除できます。要素を削除すると、スタックの数が減ります。最初に入れられた要素は常に最後に取り出され、最後に入れられた要素は常に最初に取り出されます。スタックの最下部からデータを取得することは許可されていません。また、スタックのメンバー(スタックの最上位以外のメンバー)を表示または変更することも許可されていません。

スタックメモリはコンパイラによって自動的に割り当てられて解放され、開発者はそれを制御できません。スタックメモリは通常、ローカル変数やパラメータなどを関数に格納します。関数が作成されると、これらのメモリは自動的に作成されます。関数が戻ると、これらのメモリは自動的に解放されます。

スタックはメモリ割り当てに使用でき、スタックの割り当てと回復は非常に高速です。次のコードは、メモリ割り当てにおけるブランチの役割を示しています。コードは次のとおりです。

func calc(a, b int) int {
    
    
	var c int
	c = a * b

	var x int
	x = c * 10

	return x
}

上記のコードは、いかなる状況もなしに最適化されc実行されxプロセス変数が割り当てられます。Go言語ではデフォルトcxスタックに割り当てられますが、これら2つの変数calc()は、関数の終了時、関数の終了時、メモリの保存cxスタック後の解放、スタック割り当て全体でのメモリ割り当てプロセス、およびリサイクルは非常に高速になります。

2.ヒープメモリ

マイルインメモリの割り当ては、部屋にさまざまな家具を配置するのと似ており、家具のサイズはさまざまです。

メモリを割り当てるときは、家具を配置する前に、家具を保持するのに十分なスペースを見つける必要があります。家具の出し入れを繰り返すと、部屋のスペースが乱雑になります。このとき、家具を置くスペースは存在します。十分なスペースはありますが、空間は異なるエリアに分散しており、連続したスペースはありません。家具の配置の問題に来てください。

このとき、メモリアロケータは、図に示すように、これらのスペースを調整および最適化する必要があります。

ヒープメモリヒープによって割り当てられたメモリおよびスタックによって割り当てられたメモリと比較して、ヒープは予測できないサイズのメモリ割り当てに適しています。しかし、これに支払われる代償は、割り当て速度の低下とメモリの断片化です。

ヒープメモリのライフサイクルはスタックメモリよりも長くなります。関数によって返された値が他の場所で使用される場合、この値はコンパイラによって自動的にヒープに割り当てられます。スタックメモリと比較して、ヒープメモリはコンパイラによって自動的に解放できず、ガベージコレクタによってのみ解放できるため、スタックメモリの効率は非常に高くなります。

2.エスケープ分析

スタックメモリの方が効率的であるため、最初にスタックメモリを使用する必要があります。では、Go言語は、ヒープ上の変数にジャッジを割り当てる方法、またはスタックする方法です。これにはエスケープ分析が必要です。以下では、例を使用してエスケープ分析を説明します。コードは次のとおりです。

package main

func main() {
    
    
    newString()
}

func newString() *string{
    
    
   s:=new(string)
   *s = "wohu"
   return s
}

ここで、エスケープ分析を使用して、エスケープが発生したかどうかを確認します。コマンドは次のとおりです。

wohu@ubuntu:~/gocode/src$ go build -gcflags="-m -l" demo.go
# command-line-arguments
./demo.go:12:10: new(string) escapes to heap
wohu@ubuntu:~/gocode/src$ 
  • -m エスケープ分析情報を印刷する手段。
  • -l インライン化が禁止されており、エスケープをより適切に観察できることを示します。

上記の出力から、エスケープが発生していることがわかります。つまり、ポインタを関数の戻り値として使用する場合は、エスケープが発生する必要があります。

ヒープメモリにエスケープされた変数はすぐにリサイクルできません。ガベージコレクションマークでのみクリアできるため、ガベージコレクションのプレッシャーが高まります。したがって、できるだけエスケープしないようにし、変数をスタックメモリに割り当ててリソースを確保できるようにします。関数が戻ったときにリサイクルされます。、効率を向上させます。

ここで、InewString関数は、エスケープ関数が最適化されたコードを回避するように次のように最適化されています。

func newString() string{
    
    
   s:=new(string)
   *s = "wohu"
   return *s
}

もう一度コマンドを使用して上記のコードのエスケープ分析を表示します。コマンドは次のとおりです。

wohu@ubuntu:~/gocode/src$ go build -gcflags="-m -l" demo.go
# command-line-arguments
./demo.go:8:10: newString new(string) does not escape
wohu@ubuntu:~/gocode/src$ 

分析結果から、ポインタ変数はまだ宣言されていますがs、関数はポインタを返さないため、エスケープは発生しないことがわかります。

エスケープ分析は、変数がヒープに割り当てられているかスタックに割り当てられているかを判断する方法です。実際のプロジェクトでは、GCによって速度が低下しないように、エスケープをできるだけ避けて効率を向上させる必要があります。

ヒント:エスケープ分析の観点からは、ポインターはメモリコピーを減らすことができますが、エスケープを引き起こす可能性もあるため、実際の状況に応じてポインターを使用するかどうかを選択する必要があります。

最適化スキル

  • スタックメモリの方が効率的であるため、エスケープはできるだけ避けてくださいGC必要ありませんたとえば、小さなオブジェクトを渡すパラメータarrayは、slice良い効果よりも優れています。

  • エスケープを回避できず、メモリがヒープに割り当てられている場合、頻繁なメモリアプリケーション操作では、useなどのメモリの再利用を学習する必要がありますsync.Pool

  • 時間のスペースなど、高性能を実現するための適切なアルゴリズムを選択します。

ヒント:パフォーマンスを最適化するときは、ベンチマークテストを組み合わせて、最適化が改善されたかどうかを確認する必要があります。

上記はGo、3つの方向でメモリ管理メカニズムの言語を要約したスキルに基づいています。これらの3つの一般的な方向に基づいて、基本的に必要な効果を最適化できます。さらに、ロックの使用、同時実行のロックを可能な限り狭くする、StringBuildermakestring[ ] byteconversionを使用するdeferネストしすぎないなど、できるだけ回避するためのヒントがいくつかあります

最後に推奨されたGoツールは、言語のパフォーマンス分析に付属しておりpprofCPU分析、メモリ分析、障害物分析、ミューテックス分析を表示できます

おすすめ

転載: blog.csdn.net/wohu1104/article/details/113815428