序文
Java開発者の中で、弦の高いリソース占有率はしばしばホットなトピックです。
なぜそれが高いリソースを占有しているのかを詳細に説明しましょう。
Javaでは、文字列オブジェクトが不変です。つまり、作成すると、変更できなくなります。したがって、弦をスプライスすると、新しい弦が作成され、古い文字列はゴミコレクターによってマークされます。
何百万もの文字列を処理すると、ゴミコレクターによって処理される数百万の追加の文字列を生成します。
ほとんどのチュートリアルでは、文字列に +サインを使用すると複数の文字列が生成され、パフォーマンスが低下することがわかります。 StringBuffer/StringBuilderを使用してスプライスすることをお勧めします。
しかし、これは本当にそうですか?
この記事は、JDK8で次の実験を行いました。
public static void main(string [] args){string result = ""; result += "もう少しデータ"; system.out.println(result); }javap -cを介して再コンパイルして取得します。
コード:0:ALOAD_0 //スタックに 'this'を押しますコード:0:LDC#2 //スタックに定数#2をロード2:store_1 //スタックからローカルvarを作成する(pop#2)3:new#3 //スタック6に新しいstringbuilder refを押します。 InvokeVirtual#5 // Invoke Method StringBuilder.Append()// Pop OBJ Reference + Parameter //プッシュ結果(StringBuilder Ref)14:LDC#6 //スタックで「もう少しデータ」をプッシュ16:InvokeVirtual#5 // Invoke StringBuilder.Append // Pop 19:Invokevirtual#7 / 22:Store_1 //スタックからローカルVARの作成(POP#6)23:GetStatic#8 //プッシュ値System.out:PrintStream 26:ALOAD_1 //プッシュローカル変数を押します
Javaコンパイラが生成されたバイトコードを最適化し、StringBuilderを自動的に作成し、追加操作を実行することがわかります。
最終文字列のサブストリングはコンパイル時に既に知られているため、Javaコンパイラはこの場合に上記の最適化を実行します。この最適化は静的文字列連結最適化と呼ばれ、JDK5以降有効になっています。
それは、JDK5の後、StringBuilderを手動で生成する必要がなくなり、 +サインを通じて同じパフォーマンスを達成できることを意味しますか?
動的にスプライシング文字列を試してみましょう:
動的なスプライシング文字列は、実行時にのみ知られているサブストリングを指します。たとえば、ループに文字列を追加する:
public static void main(string [] args){string result = ""; for(int i = 0; i <10; i ++){result+= "もう少しデータ"; } system.out.println(result); }また逆コンパイル:
コード:0:ALOAD_0 //スタックに 'this'を押しますコード:0:LDC#2 //スタックに定数#2をロード2:store_1 //スタックからローカルvarを作成する、pop#2 3:iconst_0 //プッシュ値0をスタック4:istore_2 //ポップ値に保存し、var 5:iload_2 // stack 6:i2 on int int int int int int int int int int int int int int int int int int int int var 5:iload_2 // LDC2_W#3 //定数10E6をスタック10に押します10:DCMPG //スタックの上に2つのダブルを比較してくださいスタック18:Invokespecial#6 // Invoke StringBuilder Constructor // Pop Object Reference 21:ALOAD_1 // PUSH LOCAL VAR 1(空の文字列)//スタック22にオンにON ON ON STACK#7 // INVOKE STRINGBUILDER.APPEND // POP OBJ REF + PARAM、PUSH RESURCE 25:LDC#8 / / invoke 27: stringbuilder.append // pop obj ref + param、push result 30:invokevirtual#9 // invoke stringbuilder.tostring // popオブジェクトリファレンス33:store_1 //スタックからローカルVARを作成する34:IINC 2、1 / ALOAD_1 // Push Local Var 1(result String)44:InvokeVirtual#11 // Invoke Methoke PrintStream.Println()// Pop Twou(Object Ref + Parameter)47:Return // Methodからreturn void
StringBuilderは14で新しくなったことがわかりますが、37歳、GOTO 5です。ループ中、最適化は達成されず、新しいStringBuildersは常に生成されていました。
したがって、上記のコードは似ています:
string result = ""; for(int i = 0; i <10; i ++){stringbuilder tmp = new StringBuilder(); tmp.append(result); tmp.append( "もう少しデータ"); result = tmp.toString();} system.out.println(result);新しいStringBuildersが常に生成されていることがわかります。ToStringを通じて、元のStringBuilderはゴミとして参照されなくなり、GCコストも増加します。
したがって、実際に使用すると、文字列が静的か動的かを区別できない場合は、StringBuilderを使用します。
参照:
http://www.pellegrino.link/2015/08/22/string-concatenation-with-java-8.html
要約します
上記は、この記事のコンテンツ全体です。この記事の内容には、すべての人の研究や仕事に特定の参照値があることを願っています。ご質問がある場合は、メッセージを残してコミュニケーションをとることができます。 wulin.comへのご支援ありがとうございます。