でも、そういう文字列処理自体があまりなかったり、実行される回数が少なければ特に問題は発生しないかもしれませんが、実はStringは効率がよくありません。効率よく処理するにはStringBufferを使います。
以下のサンプルでは、文字列の連結を200回繰り返す処理を、StringとStringBufferで実装しています。かかる時間とGC(ガベージ・コレクション)がどれだけ動くか比較してみてください。
なお、文字列連結前にSystem.gc()を2回呼び出していますが、これはなくても構いません。GCが動こうとしたタイミングでサンプルを実行すると、意図しないGCのログが出るので先に実行させています。
StringBufferTest1aActivity.java
package jp.co.triware.samples.StringBufferTest1a;
import java.util.Calendar;
import java.util.Date;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class StringBufferTest1aActivity extends Activity {
private static final String TAG = "StringBufferTest1aActivity";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final int count = 200;
Button btnString = (Button)findViewById(R.id.string_btn);
Button btnStringBuffer = (Button)findViewById(R.id.string_buffer_btn);
final TextView tvResult = (TextView)findViewById(R.id.result_tv);
btnString.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
System.gc();
System.gc();
String buf = "";
Log.d(TAG, "String: Start");
Calendar c1 = Calendar.getInstance();
for (int i = 0; i < count; i ++) {
buf += "THE QUICK BROWN FOX #" + i + " JUMPS OVER THE LAZY DOG #" + i + ".\n";
}
Calendar c2 = Calendar.getInstance();
long diff = c2.getTimeInMillis() - c1.getTimeInMillis();
Log.d(TAG, "String: End");
String msg = "String: " + diff + " ms";
Log.d(TAG, msg);
tvResult.setText(msg);
}
});
btnStringBuffer.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
System.gc();
System.gc();
StringBuffer buf = new StringBuffer();
Log.d(TAG, "StringBuffer: Start");
tvResult.setText("StringBuffer: Start");
Calendar c1 = Calendar.getInstance();
for (int i = 0; i < count; i ++) {
buf.append("THE QUICK BROWN FOX #");
buf.append(i);
buf.append(" JUMPS OVER THE LAZY DOG #");
buf.append(i);
buf.append(".\n");
}
Calendar c2 = Calendar.getInstance();
long diff = c2.getTimeInMillis() - c1.getTimeInMillis();
Log.d(TAG, "StringBuffer: End");
StringBuffer msg = new StringBuffer();
msg.append("StringBuffer: ");
msg.append(diff);
msg.append(" ms");
Log.d(TAG, msg.toString());
tvResult.setText(msg);
}
});
}
}
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<Button
android:id="@+id/string_btn"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="String"
/>
<Button
android:id="@+id/string_buffer_btn"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="StringBuffer"
/>
<ScrollView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
>
<TextView
android:id="@+id/result_tv"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
</ScrollView>
</LinearLayout>
Androidプロジェクトの設定
ビルドターゲットや最小SDKバージョンは、お使いの開発環境に合わせて設定してください。
プロジェクト名: StringBufferTest1a アプリケーション名: StringBufferTest1a パッケージ名: jp.co.triware.samples.StringBufferTest1a アクティビティーの作成: StringBufferTest1aActivity
実行結果

まずは「String」を実行してみましょう。

D/dalvikvm(529): GC_EXPLICIT freed 53K, 53% free 2569K/5379K, external 884K/1038K, paused 48ms D/dalvikvm(529): GC_EXPLICIT freed 1K, 53% free 2567K/5379K, external 884K/1038K, paused 50ms D/StringBufferTest1aActivity(529): String: Start D/dalvikvm(529): GC_CONCURRENT freed 423K, 54% free 2596K/5639K, external 884K/1038K, paused 5ms+4ms D/dalvikvm(529): GC_CONCURRENT freed 509K, 55% free 2615K/5767K, external 884K/1038K, paused 5ms+4ms D/dalvikvm(529): GC_CONCURRENT freed 486K, 55% free 2621K/5767K, external 884K/1038K, paused 5ms+4ms D/dalvikvm(529): GC_CONCURRENT freed 485K, 55% free 2630K/5767K, external 884K/1038K, paused 5ms+4ms D/dalvikvm(529): GC_CONCURRENT freed 473K, 55% free 2637K/5767K, external 884K/1038K, paused 5ms+4ms D/dalvikvm(529): GC_CONCURRENT freed 435K, 55% free 2644K/5767K, external 884K/1038K, paused 5ms+4ms D/dalvikvm(529): GC_CONCURRENT freed 474K, 55% free 2635K/5767K, external 884K/1038K, paused 5ms+4ms D/dalvikvm(529): GC_CONCURRENT freed 458K, 55% free 2639K/5767K, external 884K/1038K, paused 5ms+4ms D/dalvikvm(529): GC_CONCURRENT freed 432K, 55% free 2644K/5767K, external 884K/1038K, paused 5ms+3ms D/dalvikvm(529): GC_CONCURRENT freed 457K, 55% free 2647K/5767K, external 884K/1038K, paused 5ms+4ms D/dalvikvm(529): GC_CONCURRENT freed 419K, 54% free 2668K/5767K, external 884K/1038K, paused 5ms+3ms D/dalvikvm(529): GC_CONCURRENT freed 502K, 55% free 2673K/5831K, external 884K/1038K, paused 5ms+3ms D/dalvikvm(529): GC_CONCURRENT freed 478K, 54% free 2687K/5831K, external 884K/1038K, paused 5ms+4ms D/dalvikvm(529): GC_CONCURRENT freed 478K, 55% free 2662K/5831K, external 884K/1038K, paused 5ms+4ms D/dalvikvm(529): GC_FOR_MALLOC freed 548K, 56% free 2592K/5831K, external 884K/1038K, paused 30ms D/StringBufferTest1aActivity(529): String: End D/StringBufferTest1aActivity(529): String: 2235 ms2235ミリ秒かかって、その間にGCが15回も動いています。
次は「StringBuffer」です。

D/dalvikvm(529): GC_EXPLICIT freed 241K, 56% free 2572K/5831K, external 884K/1038K, paused 51ms D/dalvikvm(529): GC_EXPLICIT freed <1K, 56% free 2572K/5831K, external 884K/1038K, paused 44ms D/StringBufferTest1aActivity(529): StringBuffer: Start D/StringBufferTest1aActivity(529): StringBuffer: End D/StringBufferTest1aActivity(529): StringBuffer: 297 ms297ミリ秒で終わってしまいました。GCも動いていません。
StringのほうはGCが動いているために遅いとも言えるかもしれませんが、いずれにしてもStringBufferのほうが効率が良いことがわかりますね。
実行環境によってはあまり差がなかったりGCが動かなかったりするかもしれません。エミュレータでは差がはっきり出ますが、実際の端末では、あまり差がわからないかもしれません。その場合はループ回数を増やして試してみてください。実行時間に差が出ることがわかると思います。
0 件のコメント:
コメントを投稿