VPS で複数のサービス アプリケーションを実行しているが、そのうちの 1 つがすべてのリソースを占有し、ssh 経由でサーバーにアクセスできなくなる場合があります。 Kubernetes クラスターの使用に移行し、すべてのアプリケーションに制限を設定します。その後、OOM キラーがメモリの「リーク」問題を修正したため、いくつかのアプリケーションが再起動されたことがわかりました。
もちろん、OOM は常にリークの問題であるわけではなく、リソースのオーバーランになる可能性もあります。リークの問題はプログラムエラーによって引き起こされる可能性が高く、今日のテーマは、この状況を可能な限り回避する方法です。
リソースの過剰な消費はウォレットに悪影響を与える可能性があるため、すぐに行動を起こす必要があります。
次に、最適化について話しましょう。時期尚早に最適化をすべきではない理由を理解していただければ幸いです。
Go の標準的なエンティティ分類に従って、いくつかの実用的な提案を提供します。
#1. 配列とスライス事前にスライスにメモリを割り当てます 3 番目のパラメータを使用してみてください: make([]T, 0, len)<span style="font-size: 15px;"></span>
要素の正確な数がわからず、スライスの有効期間が短い場合は、より大きな要素を割り当てることができます。スライスが大きくならないようにサイズを変更します。
copy を使用することを忘れないでください2 つ以上のスライスを結合する場合など、コピーするときは append を使用しないようにしてください。
正しく反復する多くの要素または大きな要素を含むスライスの場合、for を使用して単一の要素を取得します。こうすることで、不必要な重複が回避されます。
複数のスライス受信スライスに対して何らかの操作が実行され、変更された結果が返された場合、それを返すことができます。これにより、新たなメモリ割り当てが回避されます。
スライスから小さな部分を切り取ってそれのみを使用する必要がある場合、スライスの主要部分も保持されます。正しいアプローチは、この小さなスライスの新しいコピーを使用し、古いスライスを GC にスローすることです。
文字列のスプライシングが 1 つのステートメントで完了できる場合は、 <span style="font-size: 15px;"> # を使用します。 </span>
## オペレーター。これをループ内で行う必要がある場合は、string.Builder<span style="font-size: 15px;"></span>
を使用し、その Grow<span style="font-size: 15px;"># を使用します。 </span>## メソッドは、メモリ割り当ての数を減らすために、
Builder<span style="font-size: 15px;"></span> のサイズを事前に指定します。
変換の最適化
文字列常駐
文字列をプールできるため、コンパイラが同じ文字列を 1 回だけ保存できるようになります。割り当ての回避
#fmt<span style="font-size: 15px;"> パッケージはすべてのメソッドがリフレクションを使用するため、使用しないようにしてください。 </span>
私たちが理解している小さな構造は、フィールドが 4 つ以内、マシン ワード サイズが 1 つ以内です。
#いくつかの典型的なコピー シーン
小さな構造の処理
配置を使用して構造体のサイズを削減する
4. 関数
インライン関数を使用するか、自分でインライン化しますインラインにならないものはどれか
名前付き戻り値
中間結果の保存
defer は慎重に使用してください
ヘルプ ホット パス
5. Map
メモリを事前に確保します空の構造体を値として使用する
マップは拡大のみ可能で、縮小はできません。マップをリセットする必要がある場合、その要素をすべて削除しても役に立ちません。
マップにポインターが含まれていない場合、GC は貴重な時間を無駄にすることはありません。文字列でもポインターが使用されるため、文字列の代わりにバイト配列をキーとして使用する必要があります。
同様に、ポインターは使用したくありませんが、マップとスライスを組み合わせて使用し、キーをマップとスライス内の値。このようにして、制限なく値を変更できます。
インターフェイスに値を割り当てる場合は、まずその値をどこかにコピーする必要があることに注意してください。 , 次に、ポインターを貼り付けます。重要なのはコピーすることです。インターフェイスのボックス化とボックス化解除のコストは、構造体サイズの割り当てとほぼ同じであることがわかります。
場合によっては、インターフェイスのボックス化およびボックス化解除中に割り当てが行われないことがあります。たとえば、変数や定数の小さい値やブール値、単純なフィールドが 1 つある構造体、ポインター (マップ、チャネル、関数を含む)
##他の場所と同様に、不必要な割り当てを避けるようにしてください。たとえば、2 回ボックス化する代わりに、1 つのインターフェイスを別のインターフェイスに割り当てます。
必要な場合にのみ使用してください頻繁に呼び出される関数パラメータおよび返される結果でインターフェイスを使用することは避けてください。追加の開梱作業は必要ありません。インライン化が防止されるため、インターフェイス メソッド呼び出しの使用頻度を減らします。
7. ポインタ、チャネル、境界チェック不必要な逆参照を避ける特にループ内では負荷が高すぎることが判明します。逆参照は、私たちが自費で行いたくないものです。
チャネル同期は、他の基本的な同期方法よりも時間がかかります。さらに、選択するケースが増えるほど、プログラムは遅くなります。ただし、選択、大文字と小文字、デフォルトは最適化されています。
これもコストがかかるため、避ける必要があります。たとえば、最大スライス インデックスを複数回チェック (取得) するのではなく、1 回だけチェックします。今すぐ極端なオプションを試してみるのが最善です。
この記事では、同じ最適化ルールがいくつか見られました。
コンパイラが正しい決定を下せるよう支援していただければ、コンパイラは感謝します。コンパイル時にメモリを割り当て、中間結果を使用し、コードを読みやすい状態に保つようにしてください。
#繰り返しますが、暗黙的な最適化にはベンチマークが必須です。コンパイラのバージョン間の変更が早すぎるため、昨日機能したものが明日は機能しなくなる場合や、その逆の場合も同様です。
Go の組み込みプロファイリングおよびトレース ツールを忘れずに使用してください。
以上がGo: 簡単な最適化メモの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。