byte[] -> String 変換のパフォーマンス、とAndroidでCharsetDecoder#decode(ByteBuffer in).toString()が遅い件

Android上でMessagePackのベンチマークコードを動かしつつprofile取ってみたら、msgpack-java/src/main/java/org/msgpack/unpacker/StringAccept.java at master · msgpack/msgpack-java · GitHub辺り(CharsetDecoder#decode(ByteBuffer in).toString())でほとんどの時間が掛かっているなぁ、という感じ。

で、そもそも new String(byte[] byte, String charsetName) と CharsetDecoder#decode(ByteBuffer in).toString() でどれくらい性能があるのか気になったので計測してみた。確か、new String(...) の内部で CharsetDecoder#decode() してるというのは以前調べたことがあったので、今回はどの位違ってくるのか?という点に着目。

  public static void main(String[] args) throws IOException {
    String src = "あいうえおアイウエオアイウエオaiueoAIUEO";
    byte[] raw = src.getBytes();
    ByteBuffer byteBuffer = ByteBuffer.wrap(raw);
    Charset cs = Charset.forName("UTF-8");
    int until = 10000000;

    long start = System.currentTimeMillis();
    for (int i = 0; i < until; i++) {
      cs.newDecoder().decode(byteBuffer).toString();
    }
    System.out.println("CharsetDecoder.decode(): " + (System.currentTimeMillis() - start));

    start = System.currentTimeMillis();
    for (int i = 0; i < until; i++) {
      new String(raw, "UTF-8");
    }
    System.out.println("String(byte[]): " + (System.currentTimeMillis() - start));
  }

こんなのを書いて動かして見たところ...

CharsetDecoder.decode(): 720
String(byte[]): 2367

ざっと3倍位new String(byte[] byte, String charsetName)のほうが遅かった。OpenJDK 1.6でも大体同じ。

I/XXXX    (28542): CharsetDecoder.decode(): 4366
I/XXXX    (28542): String(byte[]): 1471

同等のコードをDalvik VM上で動かしたら(ループの回数は1/100に減らした)、結果が逆転した。ちょうど三倍程度、CharsetDecoder.decodeの方が遅くなった。

この辺がmsgpack-javaAndroid上で動かすと遅くなる件と関係あるのかも。ないのかも。