Javaごみの回収を管理する5つの提案
32317 ワード
自動回転http://blog.csdn.net/wangpeng198688/article/details/50964828を削除します
【編集者によると】著者はNiv Steingartenで、Takipiです. の共同創始者で、優雅で簡潔なコードの作成に熱中しています.ゴミ収集器の紹介と整理を通じて、ゴミ回収の管理について5つの提案を提出しました.収集器の費用を下げて、プロジェクトの性能を向上させます.本論文は国内ITOM管理プラットフォームである. OneAPM エンジニアがコンパイルして整理します.
GCの低コストを維持するための最も実用的な提案は何ですか?
以前はJava 9がまもなく発表されるというニュースがありましたが、今は何度も延期されています.その中で注目すべきのはG 1(Garbage-First)ごみ収集器がHot Spot JVMのデフォルト収集器になります.シリアルコレクタからCMSコレクタまでは、ライフサイクル全体でJVMは、複数のGCの実現と更新を経てきましたが、その後、G 1コレクタは、新たなページを作成します.
ごみ収集器の持続的な発展に従って、各世代は改善と向上を行います.シリアル集成器後の並列集成器は,多核マシンの強力な計算能力を利用して,ゴミ収集マルチスレッドを実現した.その後のCMS(Concerent Mark-Sweep)収集器は、複数の段階に分けて実行され、アプリケーションスレッドの実行と同時に大量の収集が可能になり、「stop-the-world」のグローバル停止の出現頻度を大幅に低減した.現在、G 1は、JVMに大量のヒープと予測可能な均一な休止を加え、効果的に性能を向上させている.
GCは绝えず改善していますが、その致命的な弱点はやはり同じです.しかし、本論文では高効率で実用的な提案を提出しました.どのゴミ収集器を選んでも、GCオーバーヘッドを低減するのに役立ちます.
提案1:収集能力を予測する
すべてのJava標準セットと大多数のカスタム拡張実装(Troveなど) とGoogleのGuava)は、下の配列(元のものもベースのものも)を使います.データの長さが割り振られると、配列は変動しなくなりますので、多くの場合、セットの増加項目のために古い下部配列が削除され、より大きな配列を再割り当てして代替する必要があります.
ほとんどの集合実装は、集合において予想される大きな時間に設定されず、再割当プロセスを最適化し、そのオーバーヘッドを低減することを試みる.しかし、一番いい結果は、集合を構成するときに予想される大きさに設定します.
この簡単な例を見てみましょう.
しかし、新規リストに追加する項目をどのように最適化するかは難しいです.追加するたびに、このリストはまた、その下の配列が十分な空きスロットを持っていることを確認して、新しいプロジェクトをインストールすることができます.入れることができれば、次の空き溝に直接新しい項目を保存します.しかし、スペースが足りない場合は、下の配列を再割り当てし、古い配列の内容を新しい配列にコピーして、新しい項目を追加します.このプロセスは、割り当てられた複数の配列がメモリを占有し、GCが最後に回収するまでにつながる.
ですから、私たちは構築時に配列がどれぐらいの項目を収容するかを知らせます.再構成後のコードは以下の通りです.
Guavaの集合類はより先進的で、正確な数量または推定値で集合を初期化することができます.
提案2:直接処理フロー
データストリームを処理するとき、ファイルからデータを読み込んだり、インターネットからデータをダウンロードしたりします.
大きなファイルまたは未知のサイズのファイルを扱う場合、この考えは適用されません.JVMがファイルサイズのバッファを割り当てられない場合、OutOfMemoryErrrorsエラーが発生します.
しかし、データサイズが管理できるように見えても、ゴミの回収に関わると、上記のパターンはかなりの量のオーバーヘッドをもたらします.なぜならば、ファイルデータを格納するために、積み重ねの上にかなり大きなblobを割り当てています.
より良い処理は、適切なInputStream(本例ではFileInputStream)を使用して、直接にそれを分析器に送り、事前にファイル全体をバイト配列に読み込むのではなく、分析器に送ることである.すべての主要なライブラリは、APIを解析ストリームに直接暴露します.例えば、
不変性は多い優位があって、しかし1つの優位があってきわめて重視されて、それはつまり不変性はごみの回収に対する影響です.
可変オブジェクトとは、オブジェクトが作成されると、そのフィールド(この例では元のフィールドではない)が変更されなくなります.たとえば:
不変性とは、コンテナの構造が完了する前に、可変容器から引用されたすべてのオブジェクトが作成されたことを意味します.GCでは、容器は最新の新生代と一致しています.これは、新生代(young generation)に対してゴミ回収サイクルを実行すると、GCが古い年代(older generation)の中の可変でない対象をスキップすることができるということを意味しています.
オブジェクトスキャンが少ないということは、スキャンが必要なメモリページが少ないほど、メモリページスキャンが少ないということは、GCサイクルが短いということを意味し、同時に、より短いGC停止とより良い全体スループットを暗示しています.
提案4:文字列の接続を慎む
文字列は、任意のJVMベースの応用において最も一般的な非オリジナルデータ構造でありうる.しかし、その隠れた重量と便利さは、メモリの使用を大きくする原因となります.
問題は、内部連結および拘束された文字列ではなく、文字列が実行時に割り当てられ、構築されることであることが明らかである.次に、動的文字列を構築する簡単な例を見てみます.
その背後にある文法飴を見るのは簡単ではないですが、本当の舞台裏はこうです.
上記の問題を回避するための最良の方法は、StringBuiderを明確に使用し、直接にそれに付加することであり、比較的幼稚な直列演算子(「+」)を使用することではない.だからそうするべきです.
提案5:専用のオリジナルセットを使う
Javaの標準ライブラリは非常に便利で汎用的で、集合バインディング半静的タイプを使用することをサポートしています.例えば、一組の文字列(
実際に問題が発生したのは、doubleタイプの値をintタイプのリストセットまたはmapマップに置きたいからです.泛型はオリジナルのセットを呼び出すことができないので、包装タイプで代替できるので、
しかし、これは非常に無駄です.インテグ自体は完全なオブジェクトです.12バイトのオブジェクトヘッドと内部4バイトの整数フィールドを組み合わせて、インテガーオブジェクトごとに16バイトを占めます.これは同じサイズのベースタイプintの長さの4倍です.しかし、より大きな問題は、これらのIntegerが実際にゴミ回収中の対象例であることです.
この問題を解決するために、私達はTakipiにいます. で優秀なTroveコレクションを使用します.Troveは、プロの高効率メモリの元のセットをサポートするいくつかの一般的なタイプを放棄しました.例えば、無駄にしないMap
おわりに
ゴミ収集器が絶えず進歩し、リアルタイムの最適化とJITコンパイラがよりスマートになり、開発者としての私たちはコードのGC友好性にますます気を使うことができます.それでも、G 1がどんなに先進的であっても、JVMの向上については、まだ多くの問題があります.探索と実践が必要です.百尺竿頭はまだ一歩前進しなければなりません.
(コンパイル:https://www.javacodegeeks.com/2015/12/5-tips-reducing-java-garbage-collection-overhead.html)
OneAPM 端までお持ちいたします. Javaアプリケーションの性能解決策は、一般的なJavaフレームとアプリケーションサーバのすべてをサポートします.分の配置、即時体験、Java監視はこれまでこんなに簡単ではありませんでした.もっと技術的な文章を読みたいです.訪問してください. OneAPM公式技術ブログ.
【編集者によると】著者はNiv Steingartenで、Takipiです. の共同創始者で、優雅で簡潔なコードの作成に熱中しています.ゴミ収集器の紹介と整理を通じて、ゴミ回収の管理について5つの提案を提出しました.収集器の費用を下げて、プロジェクトの性能を向上させます.本論文は国内ITOM管理プラットフォームである. OneAPM エンジニアがコンパイルして整理します.
GCの低コストを維持するための最も実用的な提案は何ですか?
以前はJava 9がまもなく発表されるというニュースがありましたが、今は何度も延期されています.その中で注目すべきのはG 1(Garbage-First)ごみ収集器がHot Spot JVMのデフォルト収集器になります.シリアルコレクタからCMSコレクタまでは、ライフサイクル全体でJVMは、複数のGCの実現と更新を経てきましたが、その後、G 1コレクタは、新たなページを作成します.
ごみ収集器の持続的な発展に従って、各世代は改善と向上を行います.シリアル集成器後の並列集成器は,多核マシンの強力な計算能力を利用して,ゴミ収集マルチスレッドを実現した.その後のCMS(Concerent Mark-Sweep)収集器は、複数の段階に分けて実行され、アプリケーションスレッドの実行と同時に大量の収集が可能になり、「stop-the-world」のグローバル停止の出現頻度を大幅に低減した.現在、G 1は、JVMに大量のヒープと予測可能な均一な休止を加え、効果的に性能を向上させている.
GCは绝えず改善していますが、その致命的な弱点はやはり同じです.しかし、本論文では高効率で実用的な提案を提出しました.どのゴミ収集器を選んでも、GCオーバーヘッドを低減するのに役立ちます.
提案1:収集能力を予測する
すべてのJava標準セットと大多数のカスタム拡張実装(Troveなど) とGoogleのGuava)は、下の配列(元のものもベースのものも)を使います.データの長さが割り振られると、配列は変動しなくなりますので、多くの場合、セットの増加項目のために古い下部配列が削除され、より大きな配列を再割り当てして代替する必要があります.
ほとんどの集合実装は、集合において予想される大きな時間に設定されず、再割当プロセスを最適化し、そのオーバーヘッドを低減することを試みる.しかし、一番いい結果は、集合を構成するときに予想される大きさに設定します.
この簡単な例を見てみましょう.
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> List <span class="hljs-title" style="box-sizing: border-box;">reverse</span>(List<? extends T> list) {
List result = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> ArrayList();
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> i = list.size() - <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>; i >= <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; i--) {
result.add(list.get(i));
}
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> result;
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li></ul>
以上の方法では、新しい配列を割り当てて、他のリストの項目を塗りつぶしますが、順序を変えて塗りつぶします.しかし、新規リストに追加する項目をどのように最適化するかは難しいです.追加するたびに、このリストはまた、その下の配列が十分な空きスロットを持っていることを確認して、新しいプロジェクトをインストールすることができます.入れることができれば、次の空き溝に直接新しい項目を保存します.しかし、スペースが足りない場合は、下の配列を再割り当てし、古い配列の内容を新しい配列にコピーして、新しい項目を追加します.このプロセスは、割り当てられた複数の配列がメモリを占有し、GCが最後に回収するまでにつながる.
ですから、私たちは構築時に配列がどれぐらいの項目を収容するかを知らせます.再構成後のコードは以下の通りです.
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> List <span class="hljs-title" style="box-sizing: border-box;">reverse</span>(List<? extends T> list) {
List result = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> ArrayList(list.size());
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> i = list.size() - <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>; i >= <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; i--) {
result.add(list.get(i));
}
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> result;
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li></ul>
このようにすると、ArayListコンストラクタは最初の設定時にlist.size()のプロジェクトを収容できることを保証でき、これはメモリを反復中に再割り当てする必要がないことを意味する.Guavaの集合類はより先進的で、正確な数量または推定値で集合を初期化することができます.
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">List result = Lists.newArrayListWithCapacity(list.size());
List result = Lists.newArrayListWithExpectedSize(list.size());</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul>
第一行コードはどれぐらいの項目が記憶されるべきかを知っています.第二行は予想誤差に適応するために余分な充填を割り当てます.提案2:直接処理フロー
データストリームを処理するとき、ファイルからデータを読み込んだり、インターネットからデータをダウンロードしたりします.
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">byte</span>[] fileData = readFileToByteArray(<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> File(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"myfile.txt"</span>));</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
このように生成されたバイト配列は、XMLドキュメント、JSONオブジェクト、またはプロトコルバッファメッセージとして解析され、いくつかの共通のオプションを命名することができる.大きなファイルまたは未知のサイズのファイルを扱う場合、この考えは適用されません.JVMがファイルサイズのバッファを割り当てられない場合、OutOfMemoryErrrorsエラーが発生します.
しかし、データサイズが管理できるように見えても、ゴミの回収に関わると、上記のパターンはかなりの量のオーバーヘッドをもたらします.なぜならば、ファイルデータを格納するために、積み重ねの上にかなり大きなblobを割り当てています.
より良い処理は、適切なInputStream(本例ではFileInputStream)を使用して、直接にそれを分析器に送り、事前にファイル全体をバイト配列に読み込むのではなく、分析器に送ることである.すべての主要なライブラリは、APIを解析ストリームに直接暴露します.例えば、
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">FileInputStream fis = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> FileInputStream(fileName);
MyProtoBufMessage msg = MyProtoBufMessage.parseFrom(fis);</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul>
提案3:可変オブジェクトを使用しない不変性は多い優位があって、しかし1つの優位があってきわめて重視されて、それはつまり不変性はごみの回収に対する影響です.
可変オブジェクトとは、オブジェクトが作成されると、そのフィールド(この例では元のフィールドではない)が変更されなくなります.たとえば:
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">ObjectPair</span> {</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> Object first;
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">private</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">final</span> Object second;
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-title" style="box-sizing: border-box;">ObjectPair</span>(Object first, Object second) {
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.first = first;
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">this</span>.second = second;
}
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> Object <span class="hljs-title" style="box-sizing: border-box;">getFirst</span>() {
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> first;
}
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> Object <span class="hljs-title" style="box-sizing: border-box;">getSecond</span>() {
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> second;
}
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li></ul>
上記のクラスを実装した結果は可変オブジェクトではありません.すべてのフィールドが一旦マークされたら変更できません.不変性とは、コンテナの構造が完了する前に、可変容器から引用されたすべてのオブジェクトが作成されたことを意味します.GCでは、容器は最新の新生代と一致しています.これは、新生代(young generation)に対してゴミ回収サイクルを実行すると、GCが古い年代(older generation)の中の可変でない対象をスキップすることができるということを意味しています.
オブジェクトスキャンが少ないということは、スキャンが必要なメモリページが少ないほど、メモリページスキャンが少ないということは、GCサイクルが短いということを意味し、同時に、より短いGC停止とより良い全体スループットを暗示しています.
提案4:文字列の接続を慎む
文字列は、任意のJVMベースの応用において最も一般的な非オリジナルデータ構造でありうる.しかし、その隠れた重量と便利さは、メモリの使用を大きくする原因となります.
問題は、内部連結および拘束された文字列ではなく、文字列が実行時に割り当てられ、構築されることであることが明らかである.次に、動的文字列を構築する簡単な例を見てみます.
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> String <span class="hljs-title" style="box-sizing: border-box;">toString</span>(T[] array) {
String result = <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"["</span>;
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> i = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; i < array.length; i++) {
result += (array[i] == array ? <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"this"</span> : array[i]);
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (i < array.length - <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>) {
result += <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">", "</span>;
}
}
result += <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"]"</span>;
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> result;
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li></ul>
配列を取得し、その文字列表現を返すのは良い方法ですが、これはオブジェクト割り当ての問題点です.その背後にある文法飴を見るのは簡単ではないですが、本当の舞台裏はこうです.
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> String <span class="hljs-title" style="box-sizing: border-box;">toString</span>(T[] array) {
String result = <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"["</span>;
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> i = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; i < array.length; i++) {
StringBuilder sb1 = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> StringBuilder(result);
sb1.append(array[i] == array ? <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"this"</span> : array[i]);
result = sb1.toString();
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (i < array.length - <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>) {
StringBuilder sb2 = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> StringBuilder(result);
sb2.append(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">", "</span>);
result = sb2.toString();
}
}
StringBuilder sb3 = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> StringBuilder(result);
sb3.append(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"]"</span>);
result = sb3.toString();
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> result;
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li><li style="box-sizing: border-box; padding: 0px 5px;">16</li><li style="box-sizing: border-box; padding: 0px 5px;">17</li><li style="box-sizing: border-box; padding: 0px 5px;">18</li><li style="box-sizing: border-box; padding: 0px 5px;">19</li><li style="box-sizing: border-box; padding: 0px 5px;">20</li><li style="box-sizing: border-box; padding: 0px 5px;">21</li><li style="box-sizing: border-box; padding: 0px 5px;">22</li><li style="box-sizing: border-box; padding: 0px 5px;">23</li></ul>
文字列は可変ではないので、接続時には変更されずに新しい文字列を順次割り当てます.また、コンパイラは、標準的なStringBuiderクラスを利用して実行されるこれらのリンクです.これは二重の面倒を引き起こし、反復のたびに(1)暗黙的に臨時文字列を割り当て、(2)クリンガーオブジェクトを暗黙的に割り当てて最終結果の構築を助けてくれる.上記の問題を回避するための最良の方法は、StringBuiderを明確に使用し、直接にそれに付加することであり、比較的幼稚な直列演算子(「+」)を使用することではない.だからそうするべきです.
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> String <span class="hljs-title" style="box-sizing: border-box;">toString</span>(T[] array) {
StringBuilder sb = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> StringBuilder(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"["</span>);
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">for</span> (<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">int</span> i = <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">0</span>; i < array.length; i++) {
sb.append(array[i] == array ? <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"this"</span> : array[i]);
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">if</span> (i < array.length - <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>) {
sb.append(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">", "</span>);
}
}
sb.append(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"]"</span>);
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">return</span> sb.toString();
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li></ul>
この時、方法の開始時はSteringBuiderだけを割り当てました.この点から、すべての文字列とリスト項目が唯一のStringBuiderに追加され、最終的には一回のtostringメソッドを呼び出して文字列に変換し、結果を返します.提案5:専用のオリジナルセットを使う
Javaの標準ライブラリは非常に便利で汎用的で、集合バインディング半静的タイプを使用することをサポートしています.例えば、一組の文字列(
Set<String>
)または一対の文字列を文字列リストにマッピングする場合(Map<Pair, List<String>>
)は、標準ライブラリを直接利用するのが便利である.実際に問題が発生したのは、doubleタイプの値をintタイプのリストセットまたはmapマップに置きたいからです.泛型はオリジナルのセットを呼び出すことができないので、包装タイプで代替できるので、
List<int>
を放棄してList<Integer>
を使用するのが良い.しかし、これは非常に無駄です.インテグ自体は完全なオブジェクトです.12バイトのオブジェクトヘッドと内部4バイトの整数フィールドを組み合わせて、インテガーオブジェクトごとに16バイトを占めます.これは同じサイズのベースタイプintの長さの4倍です.しかし、より大きな問題は、これらのIntegerが実際にゴミ回収中の対象例であることです.
この問題を解決するために、私達はTakipiにいます. で優秀なTroveコレクションを使用します.Troveは、プロの高効率メモリの元のセットをサポートするいくつかの一般的なタイプを放棄しました.例えば、無駄にしないMap
<code class="language-java hljs has-numbering" style="display: block; padding: 0px; color: inherit; box-sizing: border-box; font-family: 'Source Code Pro', monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal; background: transparent;">TIntDoubleMap map = <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> TIntDoubleHashMap();
map.put(<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">7.0</span>);
map.put(-<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">1</span>, <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">9.999</span>);
...</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right-width: 1px; border-right-style: solid; border-right-color: rgb(221, 221, 221); list-style: none; text-align: right; background-color: rgb(238, 238, 238);"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li></ul>
Trove下層は元の配列の使用を実現していますので、セットを操作する際に箱詰め(int->Integer)や箱外し(Integer->int)が発生していないため、ベースクラスにオブジェクトを格納することもありません.おわりに
ゴミ収集器が絶えず進歩し、リアルタイムの最適化とJITコンパイラがよりスマートになり、開発者としての私たちはコードのGC友好性にますます気を使うことができます.それでも、G 1がどんなに先進的であっても、JVMの向上については、まだ多くの問題があります.探索と実践が必要です.百尺竿頭はまだ一歩前進しなければなりません.
(コンパイル:https://www.javacodegeeks.com/2015/12/5-tips-reducing-java-garbage-collection-overhead.html)
OneAPM 端までお持ちいたします. Javaアプリケーションの性能解決策は、一般的なJavaフレームとアプリケーションサーバのすべてをサポートします.分の配置、即時体験、Java監視はこれまでこんなに簡単ではありませんでした.もっと技術的な文章を読みたいです.訪問してください. OneAPM公式技術ブログ.