GO言語メモリ管理の詳細な分析:ごみ収集とメモリリターンメカニズムの理解
1。GO言語メモリ管理の概要
GO言語には、自動メモリ管理メカニズム、つまりガベージコレクション(GC)が組み込まれています。手動メモリ管理を必要とするC/Cなどの言語とは異なり、GOプログラマーは通常、メモリを明示的に割り当てて自由にする必要はありません。 Go's Garbage Collectorは、マークアンドスイープアルゴリズムを使用しています。基本原則は、最初にすべての到達可能な(つまり、プログラムで使用されている)オブジェクトをすべてマークし、次にマークされていないオブジェクトが占めるメモリをクリア(リサイクル)します。
GoのGCは非決定論的であることに注意する必要があります。これは、GCがいつ実行されるかを正確に制御できないことも、メモリがリサイクルされた直後にオペレーティングシステムに返されることも保証することもできません。 GOランタイムは、独自の戦略に従って適切な場合はGCをトリガーします。したがって、プログラムが実行されると、いくつかの大きなオブジェクトが参照されなくなったとしても、消費するメモリはオペレーティングシステムレベルではすぐに削減されないように見えます。
2。ゴミ収集メカニズムとメモリ収集サイクル
Go Runtime内にSysmonと呼ばれるゴルウチンがあります。プログラムの生涯を通じて継続的に実行され、定期的なチェックやガベージコレクションのトリガーなど、一連のバックグラウンドタスクを実行する責任があります。 Sysmonは、いくつかの重要なパラメーターでGCとメモリリターンを管理します。
- forcegcperiod :これは、2つの強制ガベージコレクション間の最大許容間隔を定義する内部変数です。この期間中にGCが発生しない場合、Sysmonはそれを1回発火させます。 Go 1.0.3では、この値は約2分です。これは、ヒープメモリの使用がGCトリガーのしきい値に到達しない場合でも、GCがたまに実施されることを意味します。
- scavengelimit :このパラメーターは、実行時間がオペレーティングシステムにメモリを返す前に、実行時間が無料のメモリページ(スパン)を保持する最大時間を決定します。メモリページはGOメモリ管理の基本単位であり、スパンには複数のオブジェクトを含めることができます。スパン内のすべてのオブジェクトがリサイクルされ、スパンが5分以上(GO 1.0.3で約5分)アイドル状態にある場合、GOはオペレーティングシステムに戻すことのみを検討します。
Goランタイムは、「SPAN」と呼ばれるブロックにメモリを整理します。スパンは、一連の連続メモリページで構成されています。プログラムがスパンですべてのオブジェクトを使用しなくなった場合、スパンはアイドルとしてマークされます。しかし、すぐにオペレーティングシステムに戻るのではなく、GOランタイムによって一定期間保持されます(Scavengelimitによって制御)。その後のメモリ割り当ては、これらの割り当てがフリーメモリを再利用できるため、頻繁な要求のオーバーヘッドとオペレーティングシステムへのメモリを返すことができます。
3. GOGCTRACEを介してGCの動作を観察します
GOは強力なデバッグツールを提供します。環境変数GOGCTRACE = 1を設定することにより、プログラムが実行されているときに詳細なGCログを出力し、GCの健康状態を理解するのに役立ちます。
大きなメモリブロックを繰り返し割り当てて「解放」するシナリオをシミュレートする次のサンプルコードを考えてみましょう。
パッケージメイン 輸入 ( 「FMT」 "時間" )) func main(){ fmt.println( "メモリの取得(初めて)") TMP:= make([] uint32、100000000)// 400mb KKの場合:=範囲TMP { TMP [kk] = 0 } time.sleep(5 * time.second)//短い遅延fmt.println( "Returning Memory(初回)") tmp = make([] uint32、1)//リアルロケート小さな配列をReallocate gc条件を満たす大きな配列tmp = nil // nilに設定され、明示的に大きな配列時間を参照しなくなり、睡眠(5 * second)//短い遅延fmt.println( "Memory(Second)") ") tmp = make([] uint32、10000000)// kk:= range tmp {for regain for for arecain TMP [kk] = 0 } time.sleep(5 * time.second)//短い遅延fmt.println( "Returning Memory(Second Time)") tmp = make([] uint32、1) TMP = nil time.sleep(5 * time.second) fmt.println( "プログラム終了") }
3.1短い遅延の下でGCログを観察します
上記のコードをデフォルトの短い遅延(5秒)で実行し、GOGCTRACE = 1を設定します。
gogctrace = 1 your_program.goを実行します
次のような出力が表示される場合があります(特定の値は、GOバージョンとシステム環境によって異なります)。
GC1(1):0 0 0 MS 0-> 0 MB 172-> 137(173-36)オブジェクト0ハンドオフ メモリを取得する(初めて) GC2(1):0 0 0 MS 381-> 381 MB 203-> 202(248-46)オブジェクト0ハンドオフ メモリを返す(初めて) メモリを取得する(2回目) メモリを返す(2回目) プログラムが終了しました
ログからわかるように、GCは大きなメモリの最初の割り当ての後に発射されます(GC2)が、報告されたヒープサイズ(381MB-> 381MB)は大幅に変化しません。メモリを返した後、メモリがオペレーティングシステムに返される兆候はすぐに観察されませんでした。これは、TMP = nilが大型アレイをリサイクル可能にするだけで、GCはリサイクル可能であるとマークした可能性がありますが、遅延時間が短いため、forcegcperiodおよびscavengelimitにより、メモリはオペレーティングシステムに返されていません。オペレーティングシステムレベルで観察されるメモリ使用量はまだ高く、2番目の割り当てでも「二重」である可能性があります。これは、Goランタイムが、以前はアイドルとしてマークされていたが、新しい大きなメモリを割り当てるときにまだOSに返されていないメモリを直ちに再利用するのではなく、ヒープを延長することを選択する可能性があります。
3.2長い遅延の下でGCログを観察します
forcegcperiodとscangelimitの効果を観察するために、Code.Sleep Delay.Sleep Delay in Codeの3分(つまり、3 * Minute)を変更して、forcegcperiod(約2分)とScangelimit(約5分)を超えました。
パッケージメイン 輸入 ( 「FMT」 "時間" )) func main(){ fmt.println( "メモリの取得(初めて)") TMP:= make([] uint32、100000000)// 400mb KKの場合:=範囲TMP { TMP [kk] = 0 } time.sleep(3 * time.minute)//遅延fmt.println( "リターンメモリ(初めて)") tmp = make([] uint32、1) TMP = nil time.sleep(3 * time.minute)//遅延fmt.println( "メモリの取得(2番目の時間)") tmp = make([] uint32、10000000)// kk:= range tmp {for regain for for arecain TMP [kk] = 0 } time.sleep(3 * time.minute) fmt.println( "メモリの返却(2回目)") tmp = make([] uint32、1) TMP = nil time.sleep(3 * time.minute) fmt.println( "プログラム終了") }
変更されたコードを実行し、GOGCTRACE = 1を設定すると、次のようなキーログスニペットが表示されます。
メモリを返す(初めて) # ... しばらくして... SCVG0:INUSE:1、IDLE:1、SYS:3、リリース:0、消費:3(MB) SCVG0:INUSE:381、IDLE:0、SYS:382、リリース:0、消費:382(MB) SCVG1:INUSE:1、IDLE:1、SYS:3、リリース:0、消費:3(MB) SCVG1:INUSE:381、IDLE:0、SYS:382、リリース:0、消費:382(MB) GC9(1):1 0 0 MS 1-> 1 MB 4485-> 2562(26531-23969)オブジェクト0ハンドオフ GC10(1):1 0 0 MS 1-> 1 MB 2563-> 2561(26532-23971)オブジェクト0ハンドオフ SCVG2:GC強制// ForceGC(2分)が超えました SCVG2:INUSE:1、IDLE:1、SYS:3、リリース:0、消費:3(MB) GC3(1):0 0 0 MS 381-> 381 MB 206-> 206(252-46)オブジェクト0ハンドオフ SCVG2:GC強制 SCVG2:INUSE:381、IDLE:0、SYS:382、リリース:0、消費:382(MB) メモリを取得する(2回目)
ログの解釈:
- SCVGログライン:これはメモリスカベンジャーの出力であり、オペレーティングシステムに返されるメモリのアクティビティを示しています。
- Inuse:Goが実行されたときに現在使用されているメモリ(MB)。
- アイドル:GOが実行されているときに割り当てられたが、現在無料です。
- SYS:GOが実行されたときにオペレーティングシステムから取得した合計メモリ(Inuse Idle、MB)。
- リリース:メモリ(MB)がオペレーティングシステムに戻りました。
- 消費:GOが実行されているときに現在消費されている合計メモリ(MB)。
- SCVG2:GC強制:これは、SysmonがForce GC(2分)タイムアウトによりGCを強制したことを示しています。
- メモリを返した後、遅延が十分に長い場合(Scangelimit以上)、放出されたフィールドの値が増加し、GOランタイムがフリーメモリスパンをオペレーティングシステムに戻すことを示します。たとえば、大きな配列がリリースされると、この行(または他の類似の行)は、リリースされた値がゼロ以外の値であるか、SYS値が大幅に低下することを示している場合があります。
これらのログを通して、GOのGCがメモリをリサイクルし、特定の条件が満たされた後にメモリをオペレーティングシステムに戻すことを確認できます(ScanvenGelimit Timeoutなど)。短期間、GOランタイムは、パフォーマンスを改善するために後で使用するためにリサイクルされたメモリを保持する傾向があります。
4。大規模なメモリ変数管理戦略と一般的な誤解
GOのGCメカニズムを理解することは、大きなメモリ変数を効果的に管理するために重要です。
4.1任意の割り当ての意味
サンプルコードでは、TMP = nilを使用して大きな配列を「無料」しました。これは、GCがすぐに実行されることではありませんが、参照されなくなったため、TMP変数が指すメモリ領域をマークします。そのメモリ領域を指すアクティブな参照がなくなると、GCはそれを次に実行するときにリサイクル可能なオブジェクトとして認識します。これは、メモリをすぐにリリースするのではなく、オブジェクトをGCに変える候補者にすぎません。
4.2メモリがすぐにOSに返されない理由
Goランタイムはすぐにリサイクルされたメモリをオペレーティングシステムに返すことはありません。いくつかの主な理由があります。
- パフォーマンスの最適化:オペレーティングシステムに頻繁に適用してメモリを返すことで、システムコールがオーバーヘッドになります。 Goランタイムは、自由なメモリの一部を保持する傾向があるため、これらの予約メモリからその後のメモリの割り当てをより速く取得し、システム呼び出しの頻度を減らすことができます。
- Scavengelimitメカニズム:前述のように、GOはScanvenGelimitパラメーターに従って一定期間フリーメモリスパンを保持します。スパンアイドル時間がこの制限を超えた場合にのみ、オペレーティングシステムに返されると見なされます。
- オペレーティングシステムのレポートの違い:異なるオペレーティングシステム(さまざまなツールの下で同じオペレーティングシステムでさえ)は、「メモリ使用量」がどのように統計的に異なる場合があります。たとえば、一部のツールでは、プロセスの仮想メモリサイズを報告する場合があります。これには、GoランタイムがOSから要求したメモリを含む場合がありますが、内部的には自由であるため、メモリが減少しないように見えます。一部のシステム(プラン9やWindowsの一部のバージョンなど)では、GOランタイムが内部で解放された場合でも、オペレーティングシステムレベルはメモリ使用量の低下をすぐに表示しない場合があります。
4.3 OOMを避けるための提案
大量のデータまたは長期にわたるGOプログラムを処理する場合、「メモリから外れた」例外に遭遇する可能性があります。大きなメモリ変数を管理するためのいくつかの専門的慣行を次に示します。
- GCの動作を理解する:まず第一に、GOのGCは非決定的であり、メモリがすぐにオペレーティングシステムに返されるとは期待していないことを明確にしてください。
- PPROFによるメモリ分析:メモリの問題に遭遇する場合、最も効果的なツールはGOの組み込みパフォーマンスアナライザーPPROFです。プログラムのどの部分が多くのメモリを割り当てているか、そしてメモリリークがあるかどうかを特定するのに役立ちます(つまり、もはや使用されていないメモリはまだ誤解されています)。
- 不要な割り当てを削減する:頻繁に作成および破壊される大きなオブジェクトの場合、オブジェクトプール(Sync.pool)を使用するか、大きなチャンクバッファーを事前に割り当て、多重化を行い、GC圧力とメモリの断片化を軽減します。
- ストリーミングデータ:超大規模なデータセットの場合、すべてのデータを一度にメモリにロードすることを避けてください。ストリーミングまたはチャンキング処理を使用します。データのごく一部のみが一度に処理され、GCにリサイクルする機会があることを確認するために処理後すぐにリリースされます。
- 合理的に設計データ構造:メモリ効率が高いデータ構造を選択します。たとえば、[]バイトは通常、[]文字列よりもメモリ節約です。後者には追加の文字列ヘッダーのオーバーヘッドが含まれる可能性があるためです。
- グローバルな大きな変数を避けてください。グローバルな範囲で長寿命の大きな変数を宣言しないようにしてください。必要に応じて、使用しなくなったらNILへの参照を設定し、他の参照がないことを確認してください。
- 監視とチューニング:生産環境でのGOプログラムのメモリ使用量を継続的に監視します。 GoのGCは通常うまく機能しますが、特定の高負荷シナリオでは、GOGC環境変数を通じてGCの目標率を調整する必要がある場合がありますが、通常、その影響をよく知っていない限り、自由に変更することはお勧めしません。
5。概要
GO Languageは、効率的なタグクリーニングガベージコレクターとSysmon Goroutineを介してメモリを自動的に管理します。これにより、開発者の仕事が大幅に簡素化されますが、内部メカニズムを理解することは、高性能でメモリに優しいGOプログラムを作成するために重要です。メモリリサイクルは、非同期および遅延プロセスです。 Goランタイムは、メモリを内部的にリサイクルし、ForceGcperiodやScangelimitなどのパラメーターに基づいて、適切な時期にオペレーティングシステムに戻します。 GOGCTRACEを使用すると、GCアクティビティを詳細に観察できます。PPROFは、記憶の問題を診断するための強力なツールです。不必要な割り当ての削減、オブジェクトの多重化、ストリーミングデータなど、優れたメモリ管理の実践に従うことで、GOのメモリ管理機能をより効果的に利用し、潜在的なメモリボトルネックを回避することができます。
以上がGO言語メモリ管理の詳細な分析:ごみ収集とメモリリターンメカニズムの理解の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

Undress AI Tool
脱衣画像を無料で

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Stock Market GPT
AIを活用した投資調査により賢明な意思決定を実現

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

この記事は、GOを使用してWebSocketを開発するときに遭遇するEOF(ファイルの終了)エラーを解決することを目的としています。通常、このエラーは、サーバーがクライアントメッセージを受信し、接続が予期せず閉じられている場合に発生し、その後のメッセージを正常に配信できません。この記事では、問題の原因を分析し、コードの例を提供し、対応するソリューションを提供して、開発者が安定した信頼できるWebSocketアプリケーションを構築できるようにします。

この記事では、GOプログラムで外部エディター(VIMやNanoなど)を開始し、プログラムが実行され続ける前にユーザーがエディターを閉じるのを待つ方法について説明します。 cmd.stdin、cmd.stdout、およびcmd.stderrを設定することにより、編集者は端末と対話して、起動の障害の問題を解決できます。同時に、完全なコードの例が表示され、開発者がこの機能をスムーズに実装するのに役立つ予防策が提供されます。

Goprovidessimpleandefficientfilehandlingusingtheosandbufiopackages.Toreadasmallfileentirely,useos.ReadFile,whichloadsthecontentintomemorysafelyandautomaticallymanagesfileoperations.Forlargefilesorincrementalprocessing,bufio.Scannerallowsline-by-liner

struct {}はgoのフィールドレス構造であり、ゼロバイトを占有し、データが不要なシナリオでよく使用されます。 Goroutine同期など、チャネル内の信号として使用されます。 2。効率的なメモリの重要な存在チェックを実現するために、値の種類のコレクションとして使用されます。 3.依存関係の注入または組織機能に適した定義可能なステートレスメソッドレシーバー。このタイプは、制御フローと明確な意図を表現するために広く使用されています。

標準ライブラリのエンコード/JSONパッケージを使用して、JSON構成ファイルを読み取ります。 2。GOPKG.in/Yaml.v3ライブラリを使用して、YAML形式の構成を読み取ります。 3. os.getenvまたはgodotenvライブラリを使用して、ファイル構成を上書きします。 4. Viperライブラリを使用して、マルチフォーマット構成、環境変数、自動リロードなどの高度な機能をサポートします。タイプの安全性を確保し、ファイルと解析エラーを適切に処理し、構造タグマッピングフィールドを正しく使用し、ハードコーディングパスを避け、環境変数または生産環境での安全な構成ストレージを使用することをお勧めするために、構造を定義する必要があります。単純なJSONから始めて、要件が複雑な場合にViperに移行できます。

ミドルウェアワーシングウェブシュアレーバーは、interceptttprequestSeyreatheyreachtheTheTheHandlerを使用して、カットカッティングの機能性を有効にします

この記事の目的は、開発者がAES暗号化にGO言語のCFB(CIPHERフィードバック)モードを使用するときに遭遇する可能性のあるXorkeyStream機能によって引き起こされるゼロのポインターの例外を理解し、解決するのを支援することです。エラーの一般的な原因を分析し、正しいコードの例を提供することにより、暗号化プロセスがスムーズに進むようにします。焦点は、初期化ベクトル(IV)の正しい使用と、AESブロックサイズを理解することの重要性にあります。

ARMアーキテクチャ用のGOコードをコンパイルするには、環境変数を設定してGoBuildコマンドを使用します。 1。ターゲットプラットフォームを指定するには、Goos = LinuxとLinuxとGoarch = ARM(32ビット)またはARM64(64ビット)を設定します。 2.オプションで、ARMV7命令セットを指定するには、32ビットアームのGOARM = 7を設定します。 3. CGOが不要な場合は、静的リンクを確保するためにCGO_ENABLED = 0を設定します。 4。Goos= LinuxGoarch = ARM64CGO_ENABLED = 0GOBUILD-OMYAPP-ARM64などのコマンドを実行して、バイナリファイルを生成します。 5。生成されたバイナリファイルをアームデバイスにコピーします(ラズバーなど
