ホームページ >バックエンド開発 >Golang >Golang GC ガベージコレクションの仕組みの詳細な説明

Golang GC ガベージコレクションの仕組みの詳細な説明

藏色散人
藏色散人転載
2020-09-14 09:47:083398ブラウズ

次のコラム golang チュートリアル では、Golang GC ガベージ コレクションのメカニズムについて詳しく説明します。困っている友人の役に立てば幸いです。

Golang GC ガベージコレクションの仕組みの詳細な説明

#まとめ

go In の実際の使い方この言語を学習する過程で、一見奇妙なメモリ使用現象に遭遇したため、Go 言語のガベージ コレクション モデルについて調査することにしました。この記事はその研究結果をまとめたものです。

ガベージ コレクションとは何ですか?

かつて、メモリ管理はアプリケーションを開発するプログラマにとって大きな問題でした。従来のシステムレベルのプログラミング言語 (主に C/C) では、プログラマはメモリを注意深く管理し、メモリの適用と解放を制御する必要がありました。注意しないとメモリ リークが発生する可能性があり、この種の問題は見つけて見つけるのが難しく、開発者にとっては常に悪夢でした。この頭痛の問題を解決するにはどうすればよいでしょうか?以前は、

    メモリ リーク検出ツールの 2 つの方法が一般的に使用されていました。このツールの原理は一般に静的コード スキャンであり、スキャナを使用してメモリ リークを引き起こす可能性のあるコード セグメントを検出します。しかし、検出ツールには必ず漏れや欠点があり、補助的な役割しか果たせません。
  • スマート ポインタ。これはcで紹介した自動メモリ管理方法で、自動メモリ管理機能を備えたポインタオブジェクトを介してオブジェクトを参照することで、プログラマはメモリの解放をあまり意識する必要がなく、メモリの自動解放の目的を達成することができます。この方法は最も広く使用されていますが、プログラマーにとっては一定の学習コストがかかり (言語レベルでのネイティブ サポートではありません)、使用するのを忘れた場合にはメモリ リークを避けることはできません。
この問題を解決するために、その後開発されたほぼすべての新しい言語 (Java、Python、php など) は、言語レベル、つまり言語での自動メモリ管理を導入しました。ユーザーが注意する必要があるのは、メモリを申請するときにメモリの解放について心配する必要はなく、メモリの解放は仮想マシンまたはランタイムによって自動的に管理されます。使用されなくなったメモリ リソースを自動的にリサイクルすることをガベージ コレクションと呼びます。

一般的なガベージ コレクション メソッド

参照カウント

これは最も単純なガベージ コレクション アルゴリズムであり、前述のスマート ポインターに似ています。各オブジェクトの参照カウントを維持します。オブジェクトを参照しているオブジェクトが破棄または更新されると、参照されるオブジェクトの参照カウントは自動的に 1 つ減ります。参照されるオブジェクトが作成されるか、別のオブジェクトに割り当てられると、参照カウントは自動的に増加します。一つ。参照カウントが 0 に達すると、オブジェクトはすぐにリサイクルされます。

この方法の利点は、実装が簡単で、メモリが適時にリサイクルされることです。このアルゴリズムは、iOS の Cocoa フレームワーク、php、Python など、メモリが限られていてリアルタイム パフォーマンスが高いシステムで広く使用されています。単純な参照カウント アルゴリズムにも、明らかな欠点があります。

    参照カウントを頻繁に更新すると、パフォーマンスが低下します。簡単な解決策は、コンパイラが隣接する参照カウントの更新操作を 1 つの更新にマージすることです。もう 1 つの方法は、頻繁な一時変数の参照をカウントせず、スタックをスキャンして参照が 0 に達したかどうかを確認することです。それらを解放するかどうか。他にも様々な方法がありますので、詳しくはこちらをご覧ください。
  • 循環参照の問題。オブジェクト間で循環参照が発生すると、参照チェーン内のオブジェクトを解放できなくなります。最も明白な解決策は、循環参照を避けることです。たとえば、Cocoa では、強いポインタと弱いポインタという 2 つのポインタ型が導入されています。または、システムが循環参照を検出し、循環チェーンを積極的に切断します。もちろん、これによりガベージ コレクションの複雑さも増加します。
マークとスイープ

このメソッドは 2 つのステップに分かれています。マークはルート変数から始まり、すべての参照オブジェクトを反復処理します。アプリケーション トラバーサルを通じてアクセスできるオブジェクトの場合はすべてのオブジェクトですマーク付けが完了すると、クリア操作が実行され、マークされていないメモリがリサイクルされます (リサイクルにはデフラグ操作が伴う場合があります)。この方法は参照カウントの欠点を解決しますが、明らかな問題もあります。ガベージ コレクションが開始されるたびに、現在の通常のコードの実行がすべて一時停止され、リサイクルによりシステムの応答性が大幅に低下します。もちろん、この問題を最適化するために、マーク&スイープ アルゴリズムの多くの変形 (3 色マーキング方法など) が登場しました。

世代コレクション (世代)

実際に多数の観察を行った結果、オブジェクト指向プログラミング言語では、ほとんどのオブジェクトのライフ サイクルが非常に短いことがわかりました。世代別コレクションの基本的な考え方は、ヒープを世代と呼ばれる 2 つ以上のスペースに分割することです。新しく作成されたオブジェクトは、いわゆる若い世代に格納されます (一般に、若い世代のサイズは古い世代よりもはるかに小さくなります)。ガベージ コレクションが繰り返し実行されると、ライフ サイクルの長いオブジェクトが昇格されます (プロモーション) )古い世代へ。そこで、新世代ガベージ コレクションと旧世代ガベージ コレクションという 2 つの異なるガベージ コレクション方法が登場し、それぞれの空間内のオブジェクトに対してガベージ コレクションを実行します。新世代のガベージコレクションの速度は旧世代に比べて数桁高速であり、ガベージコレクションの頻度が高くなっても実行効率は旧世代より優れています。これは、ほとんどのオブジェクトのライフ サイクルが非常に短いためであり、古い世代に昇格する必要はまったくありません。

GO のガベージ コレクター

Go 言語のガベージ コレクションは、通常、古典的なマーク アンド スイープ アルゴリズムを使用します。

  • バージョン 1.3 より前は、golang のガベージ コレクション アルゴリズムは非常に粗雑で、そのパフォーマンスも広く批判されていました。特定の条件下 (メモリがしきい値を超えるか、定期的に (2 分など))、go ランタイムはすべてのタスクを一時停止し、実行し、マーク&スイープ操作を実行し、操作の完了後にすべてのタスクの実行を開始します。大量のメモリが使用されるシナリオでは、Go プログラムはガベージ コレクションの実行時に非常に明らかなスタック現象 (Stop The World) を経験します。高い応答速度が必要なバックグラウンド サービス プロセスでは、この種の遅延はまったく許容できません。この期間中、本番環境で Go 言語を練習していた国内外の多くのチームが、多かれ少なかれ gc の落とし穴を踏んでしまいました。当時、この問題を解決する一般的な方法は、自動的に割り当てられるメモリの量をできるだけ早く制御して gc の負荷を軽減し、手動メモリ管理を使用して大量のメモリと高頻度の割り当てを必要とするシナリオを処理することでした。
  • バージョン 1.3 以降、go チームは GC のパフォーマンスの継続的な改善と最適化を開始しており、go の新しいバージョンがリリースされるたびに、GC の改善に全員の注目が集まるようになりました。バージョン 1.3 では、go ランタイムはマーク操作とスイープ操作を分離します。以前と同様に、最初にすべてのタスクの実行を一時停止し、マークを開始します。マークが完了すると、一時停止されたタスクをすぐに再開します。代わりに、スイープ タスクとスイープ タスクを許可します。通常のコルーチン タスク他のタスクと並行して実行されます。マルチコア プロセッサ上で実行されている場合、go はビジネス コードの実行に影響を与えることなく、別のコア上で gc タスクを実行しようとします。 Go チーム自身の声明では、一時停止時間が 50% ~ 70% 短縮されたとのことです。
  • バージョン 1.4 (最新の安定バージョン) では、gc のパフォーマンスに多くの変更は加えられていません。バージョン 1.4 では、多くのランタイム コードがネイティブ C 言語実装を Go 言語実装に置き換えました。gc に加えられた大きな変更は、正確な gc を実現できることです。 C言語実装ではgc時にメモリ上のオブジェクト情報を取得できないため、通常の変数とポインタを正確に区別することができず、通常の変数はポインタとしてしか扱えません。この通常の変数が指す空間に万が一他のオブジェクトがあった場合の場合、このオブジェクトはリサイクルされません。 Go 言語実装はオブジェクトの型情報を完全に認識しており、マーク付け時にポインタが指すオブジェクトのみをトラバースするため、C 実装でのヒープ メモリの無駄が回避されます (約 10 ~ 30% を解決)。
  • バージョン 1.5 では、go チームは gc に大幅な改良を加えました (書き込みバリアの導入など、1.4 で予兆が示されています) 公式の主な目標は遅延を減らすことです。 Go 1.5 で実装されているガベージ コレクターは、「非世代、非移動、同時実行、3 色のマーク アンド スイープ ガベージ コレクター」です。世代別アルゴリズムは上で言及されており、比較的優れたガベージ コレクション管理戦略です。ただし、バージョン 1.5 には実装されていません。私の推測では、ステップが大きすぎてはならず、徐々に改善する必要があると考えられます。Go 関係者も次のように述べています。バージョン 1.6 の gc 最適化で検討され、実装される予定です。同時に、上で紹介した 3 色マーキング方法を導入し、この方法のマーク操作は毎回メモリ空間全体をスキャンすることなく徐々に実行できるため、ワールドの停止時間を短縮できます。このことから、g​​o のガベージ コレクションのパフォーマンスはバージョン 1.5 までずっと向上していることがわかります。ただし、比較的成熟したガベージ コレクション システム (java jvm や javascript v8 など) では、go を最適化するにはまだ長い道のりがあります (ただし、未来はきっと素晴らしいと信じていますよ~)。

実践経験

チームは、go 言語を練習するときに、メモリの問題 (主に gc) という最も困難な問題にも遭遇しました。遭遇した問題と経験は次のとおりです。要約すると、誰でもコミュニケーションやディスカッションを歓迎します。

go プログラムの大量のメモリ使用の問題

この問題は、バックグラウンド サービスのストレス テストを実施したときに発見されました。バックグラウンド サービスにアクセスするための多数のユーザー リクエストをシミュレートしました。現時点では、各サービス モジュールでメモリ使用量の大幅な増加が観察されます。ただし、ストレス テストを停止しても、メモリ使用量は大幅に減少しませんでした。 gprof などのさまざまな方法を使用して問題を特定するのに長い時間がかかりましたが、依然として原因は見つかりませんでした。最終的に、この時点ではそれが正常であることがわかりました...主な理由は 2 つあります。

まず、go のガベージ コレクションにはトリガーのしきい値があり、メモリ使用量が増加するたびに徐々に増加していきます (たとえば、最初のしきい値は 10MB、次は 20MB、次は 40MB になります)。 ..) 、gc go が長期間トリガーされなかった場合、アクティブに 1 回 (2 分) トリガーされます。ピーク時にメモリ使用量が増加した後は、メモリの適用を継続しない限り、しきい値に基づいて gc をトリガーすることはほとんど不可能になり、アクティブな gc が開始されるまで最大 2 分間待ってから gc をトリガーする必要があります。

2 番目の理由は、Go 言語がメモリをシステムに返すとき、そのメモリはもう必要ないのでリサイクルできることをシステムに伝えるだけであり、同時にオペレーティング システムは「遅延」戦略。すぐにはリサイクルしませんが、システム メモリが不足するまで待ってからリサイクルを開始します。そのため、プログラムがメモリを再申請するときに、非常に高速な割り当て速度を得ることができます。

長い gc 時間の問題

ユーザーがイベントに応答する必要があるバックエンド プログラムにとって、golang の gc 中にパートタイムで世界を停止することは悪夢です。上記の紹介によると、上記の改善が完了した後、go のバージョン 1.5 の gc パフォーマンスは大幅に向上しますが、すべてのガベージ コレクション言語は gc 中にパフォーマンスの低下に直面することは避けられません。一時ヒープを頻繁に作成するオブジェクト (&abc{}、new、make など) は、ガベージ コレクション中のスキャン時間を短縮します。頻繁に使用する必要がある一時オブジェクトについては、配列キャッシュを通じて直接再利用することを検討してください。 cgo メソッドを使用してメモリ自体を管理し、ガベージ コレクションをバイパスします。この方法は、絶対に必要な場合を除いて推奨されません (予期せぬ問題が発生しやすいため)。もちろん、強制する場合は検討することもできます。このメソッドはまだ非常に明白です~

ゴルーチンの質問によってリークされました

私たちのサービスの 1 つは、多くの長い接続リクエストを処理する必要があります実装中に、長い接続リクエストごとに読み取りおよび書き込みコルーチンが開かれます、無限の for ループを使用してデータの送受信を継続的に処理します。リモート エンドによって接続が閉じられた場合、これら 2 つのコルーチンが処理されないと、コルーチンは引き続き実行され、占有されているチャネルは解放されません。ここでは十分に注意する必要があり、使用しなくなった後は削除する必要があります。依存チャネルを閉じて、コルーチン内でチャネルが閉じられているかどうかを確認して、確実に終了します。

Golang-gc の基礎知識

APR 30TH, 2016 8:02 PM | COMMENTS

このパートでは主に golang gc の入門知識を紹介します。まだまだありますので、少しずつ整理していきます。

Golang GC の背景

  • Golang は、その設計原理であるガベージ コレクションに基づいた言語です。
  • ガベージ コレクターを備えた言語であるため、プログラムとの gc 対話の効率はプログラム全体の動作効率に影響します。
  • 通常、プログラム自体のメモリ管理は gc とプログラム間の効率に影響を与え、パフォーマンスのボトルネックを引き起こすこともあります。

Golang GC 関連の問題

主なリファレンスは次のとおりです:

http://morsmachine.dk/machine-gc

は 14これは 2000 年に書かれたもので、当時の gc メカニズムは比較的単純だったと推定されています。新しいバージョンの golang では、gc にさらに大きな変更が加えられるはずです。

go 言語の golang gc に関する関連部分もあります。読書メモ

メモリ リークについて

「メモリ リーク」という用語には馴染みがあるように思えますが、実際にはその正確な意味を見たことがありません。

メモリ リーク は、オペレーティング システムの観点から説明されます。鮮やかな比喩は、「オペレーティング システムがすべてのプロセスに提供できる記憶域 (仮想メモリ空​​間) が使用されている」ということです。 「ドレイン」の理由は、プログラムの実行中、記憶域スペースが継続的に動的に開かれ、操作の完了後にこれらの記憶域スペースが時間内に解放されないためです。アプリケーションがメモリの特定のセグメントを割り当てた後、設計エラーにより、プログラムがメモリ セグメントの制御を失い、メモリ スペースが無駄になる可能性があります。

プログラムがメモリ空間内のメモリの一部を適用した場合、このメモリ空間はプログラムの実行終了後に解放されず、対応するプログラムには適用された領域の適用を実行する適切な gc メカニズムがありません。リサイクルするとメモリ リークが発生します。

ユーザーの観点から見ると、メモリ リーク自体はユーザーの機能に影響を与えないため害はありませんが、「メモリ リーク」が発生すると

C および C 言語の場合ガベージ コレクションを使用しない場合、主に 2 種類のメモリ リーク、

  • ヒープ リークに焦点を当てます。メモリとは、プログラムの実行中に必要に応じて malloc や realloc new などによってヒープから割り当てられたメモリのことで、完了後は対応する free または delete を呼び出して削除する必要があります。プログラムの設計ミスにより、この部分のメモリが解放されなかった場合、そのメモリは今後使用されなくなり、ヒープ リーク (
  • システム リソース リーク (リソース リーク)) が発生します。主にプログラムのシステム使用量を指します。ビットマップ、ハンドル、ソケットなどの割り当てられたリソースが、対応する機能を使用して解放されないため、システム リソースが無駄に浪費され、システム パフォーマンスの低下やシステムの不安定化につながる可能性があります。手術。

メモリ リークには関連する問題が数多くありますが、ここでは説明しません。

一般的な GC モード

具体的な利点と欠点については、これを参照してください。ここでは一般的な概要を示します。

  • 参照カウント (参照カウント) 各オブジェクトは参照カウンタを保持しており、そのオブジェクトを参照しているオブジェクトが破棄または更新されると、参照先オブジェクトの参照カウンタは自動的に 1 減算されます。オブジェクトが作成されるか、別のオブジェクトに割り当てられると、参照は 1 になり、参照が 0 になるとリサイクルされます。考え方は単純ですが、参照カウンタが頻繁に更新されるとパフォーマンスが低下し、参照するサイクルが発生します ( php、Python で使用)
  • マークとスイープは golang が使用するものです. ルート変数からすべての参照オブジェクトを走査し、マーク後にクリア操作を実行し、マークされていないオブジェクトをリサイクルします. 欠点: すべての通常の操作は、それぞれの処理中に中断されますガベージ コレクション。コードを実行すると、システムの応答性が大幅に低下します。さまざまなマーク&スワンプのバリアント (3 色のマーキング方法) により、パフォーマンスの問題を軽減できます。
  • 世代回収(ジェネレーション)jvmは世代リサイクルの考え方を採用しています。オブジェクト指向プログラミング言語では、ほとんどのオブジェクトのライフサイクルは非常に短いです。世代別コレクションの基本的な考え方は、ヒープを世代と呼ばれる 2 つ以上のスペースに分割することです。新しく作成されたオブジェクトは、若い世代と呼ばれるものに保存されます (一般に、新しい世代のサイズは古い世代よりもはるかに小さくなります)。ガベージ コレクションが繰り返し実行されると、ライフ サイクルは次のようになります。オブジェクトは古い世代に昇格されます (ここでは分類の考え方が使用されており、これは科学的思考の基本的な考え方でもあります)。

そこで、新世代ガベージ コレクションと旧世代ガベージ コレクションという 2 つの異なるガベージ コレクション方法が登場しました (まず分類し、次に適切な薬を処方します)。オブジェクトをそれぞれのスペースに配置し、リサイクルします。新世代のガベージコレクションの速度は旧世代に比べて数桁高速であり、ガベージコレクションの頻度が高くなっても実行効率は旧世代より優れています。これは、ほとんどのオブジェクトのライフ サイクルが非常に短いためであり、古い世代に昇格する必要はまったくありません。

golang の gc は通常どのように動作するか

golang の gc は基本的にマークをクリアするという考え方です:

メモリ ヒープ内 (メモリが管理される場合があるため)ヒープ データ構造はページの作成時に使用されるため、ヒープ メモリと呼ばれます) には、他のオブジェクトに関連する可能性のある一連のオブジェクト (これらのオブジェクト間の参照) が格納されます。トレース ガベージ コレクターは、特定の時点で、実行中のプログラムをスキャンすると、ランタイムがすでに認識している既知のオブジェクトのセットがスキャンされます (通常、それらはスタック内に存在するグローバル変数とさまざまなオブジェクトです)。 gc は、これらのオブジェクトをマークし、これらのオブジェクトのステータスを到達可能としてマークし、現在のオブジェクトから到達できる他の場所にあるオブジェクトの参照をすべて検索し、これらのオブジェクトを到達可能なオブジェクトとしてマークします。このステップはマーク フェーズと呼ばれます。このステップの主な目的は、これらのオブジェクトのステータス情報を取得することです。 これらすべてのオブジェクトがスキャンされると、gc はすべての到達不能オブジェクト (到達不能ステータスを持つオブジェクト) を取得し、それらをリサイクルします。このステップはスイープ フェーズと呼ばれ、

クリーニング フェーズ

と呼ばれます。 gc は、到達可能としてマークされていないオブジェクトのみを収集します。 gc が参照を認識しない場合、まだ使用されているオブジェクトが最終的にリサイクルされ、プログラム実行エラーが発生する可能性があります。

スキャン、リサイクル、クリーニングという 3 つの主要な手順を確認できます。

他の言語に比べて、golang のガベージ コレクション モデルは比較的シンプルだと思います。

gc の問題点

gc の導入により、メモリの再利用の問題が解決されたと言えます。新しく開発された言語 (java、python、php など) を使用する場合、ユーザーはメモリ オブジェクトの解放を気にする必要はなく、オブジェクトの適用のみを気にするだけでよく、ランタイムまたは vm で関連する操作を実行します。 , メモリ領域を自動的に管理する効果を実現するために、使用されなくなったメモリ リソースを

自動的にリサイクル

するこの動作は、ガベージ コレクションと呼ばれます。 前の記述によると、gc が参照を適切に識別できるかどうかが gc が正常に動作するための基礎となるため、最初の質問は、gc が参照をどのように識別するかということです。

最大の問題: 参照を識別するのが難しく、マシンコードが何を参照としてカウントするかを認識するのは困難です。参照を誤って逃した場合、解放する準備ができていなかったメモリが誤って解放されてしまうため、戦略は、エラーを少なくするよりも多くすることです。

1 つの戦略は、すべてのメモリ空間を参照 (ポインタ値) の可能性があるものとして扱うことです。これは、保守的なガベージ コレクター (保守的なガベージ コレクター) と呼ばれます。これは、C の Boehm ガベージ コレクターがどのように動作するかです。つまり、メモリ内の通常の変数はポインタとして扱われ、すべてのポインタをカバーしようとします。通常の変数値が指す空間に偶然他のオブジェクトが存在する場合、このオブジェクトはリサイクルされません。 Go 言語の実装はオブジェクトの型情報を完全に認識しており、マークするときにポインタが指すオブジェクトのみをトラバースするため、C 実装でのヒープ メモリの無駄が回避されます (約 10 ~ 30% を解決)。

3色マーキング

2014/6 1.3 同時クリーニングの導入(ガベージコレクションとユーザーロジックの同時実行?)

2015/8 1.5 3色マーキング方式の導入

同時クリーニングの導入については、こちらを参照してください。バージョン 1.3 では、go ランタイムはマーク操作とスイープ操作を分離しました。以前と同様に、すべてのタスクの実行が最初に一時停止され、マークが開始されます (マーク部分には引き続き元のプログラムが停止している場合)、中断されたタスクはマーク完了後すぐに再開され、スイープタスクは通常のコルーチンタスクと同様に他のタスクと並行して実行されます。マルチコア プロセッサで実行されている場合、go はビジネス コードの実行に影響を与えることなく、別のコアで gc タスクを実行しようとします。go チーム自体は、一時停止時間が 50% ~ 70% 削減されると言っています。

基本的なアルゴリズムは前述のクリーニングとリサイクルですが、Golang gc 最適化の核心は STW (Stop The World) 時間をどんどん短くすることです。

GC の測定方法

これまでにたくさん述べましたが、GC のスター効率を測定し、それがプログラムの実行に影響を与えるかどうかを判断するにはどうすればよいでしょうか?最初の方法は、godebug の環境変数を設定することです。詳細については、この記事を参照してください。これは非常に良い記事です: リンク。たとえば、 GODEBUG=gctrace=1 ./myserver を実行します。出力結果を理解するには、gc の原理をさらに詳細に分析する必要があります。この記事の利点は、golang の gc 時間を決定する要因が明確に示されているため、別のターゲットを取得することもできることです。 gc 時間を改善する方法:

前回の分析によると、golang の gc はクリアマーク方式を使用していることもわかり、gc の合計時間は次のようになります:

Tgc = Tseq Tmark Tweak(T は時間を表します)

  • Tseq は、ユーザーの goroutine を停止し、いくつかの準備アクティビティ (通常は非常に小さい) を実行するのに必要な時間を表します
  • Tmarkはヒープ マーキング時間です。マーキングはすべてのユーザーのゴルーチンが停止したときに発生するため、処理のレイテンシーに大きな影響を与える可能性があります。
  • その後、粒度はさらに細分化され、具体的な概念はまだ不明です。

Tmark に関連: 1 ガベージ コレクション プロセス中に、ヒープ内のアクティブ オブジェクトの数、2 ポインターを持つアクティブ オブジェクトによって占有されるメモリの合計量、3 アクティブ オブジェクト内のポインターの数。

    Tweak に関連: 1 ヒープ メモリの総量 2 ヒープ内のガベージの総量
  • GC チューニングの実行方法 (gopher カンファレンス Danny)
ハードパラメータ

アルゴリズムの問​​題に関しては、常にいくつかのパラメータが存在します。 GOGC パラメータは主に、次の gc が開始されるときのメモリ使用量

を制御します。

たとえば、現在のプログラムは 4M のメモリ (ここでは ヒープ メモリ ) を使用しており、これは、プログラムが現在到達可能なメモリが 4M であることを意味します。到達可能* (1 GOGC/100)=8M の場合、gc がトリガーされ、関連する gc 操作が開始されます。

GOGC のパラメータをどのように設定するかは、GC の頻度を減らすために GOGC パラメータを増やすなど、本番環境の実際のシナリオに応じて決定する必要があります。 ヒント

詳細な洞察を得るには、gdb を使用することが不可欠です。この記事では、gdb の使用に関するいくつかの入門ヒントをまとめました。

オブジェクト割り当ての削減

いわゆるオブジェクト割り当ての削減とは、実際にはオブジェクトの再利用を試みることです。たとえば、次の 2 つの関数定義:

最初の関数には仮パラメータがなく、呼び出されるたびに [] バイトが返されます。2 番目の関数には、呼び出されるたびに buf の仮パラメータがあります。[ ]byte 型オブジェクトの場合は、読み取られたバイト数を返します。 最初の関数は呼び出されるたびにスペースを割り当てるため、gc にさらなる負荷がかかります。 2 番目の関数は、呼び出されるたびに仮パラメータ宣言を再利用します。

文字列と [] バイトの変換に関する決まり文句

文字列と [] バイト間の変換は gc に負担をかけます。gdb を通じて、まず 2 つのデータ構造を比較できます。

両者を変換すると、基になるデータ構造がコピーされるため、gc 効率が低下します。解決策の 1 つの方法は、特にデータ送信では常に []byte を使用することです。[]byte には、文字列で一般的に使用される効果的な演算も数多く含まれています。もう 1 つは、コピーを避けるために、下位レベルの操作を使用して直接変換することです。主に unsafe.Pointer を直接変換に使用する WeChat「Yuhen Academy」のパフォーマンス最適化の前半部分を参照できます。

unsafe の使い方については別記事にまとめられそうな気がするので、まずはここに関連情報を列挙してみます http://studygolang.com/articles/685 直感的に unsafe.Pointer Into void が理解できると思います※C、golangでは各種ポインタを変換するブリッジに相当します。

uintptr の基礎となる型は int で、ポインタが指すアドレスの値を保持できます。 unsafe.Pointer との間で変換できます。主な違いは、uintptr はポインター操作に参加できるのに対し、unsafe.Pointer はポインター変換のみを実行でき、ポインター操作は実行できないことです。ポインタ演算に golang を使用したい場合は、これを参照してください。特定のポインター操作を実行する場合、オフセットなどのさらなる計算を行う前に、まず uintptr 型に変換する必要があります。

文字列の接続には控えめに使用する 文字列の接続に使用すると新しいオブジェクトが生成され、gc の効率が低下するため、append 関数を使用するのが最善の方法です。

しかし、別の欠点もあります。たとえば、次のコードを参照してください。

追加操作を使用すると、配列のスペースが 1024 から 1312 に増加します。幸いなことに、最初に領域を割り当てるときに領域計画が行われるため、コード管理コストが増加し、GC への負荷が軽減され、コード効率が向上します。

以上がGolang GC ガベージコレクションの仕組みの詳細な説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はcsdn.netで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。