雨谷の日和

過去20年で2,700を超えるアニメの第1話だけは見続けた僕のお勧めアニメがハズレなはずがない

Javaでのバイナリ出力(バッファリング有/最適化無)

バイナリ出力にバッファリングを実装するにはBufferedOutputStreamを用いる。
具体的には、以下のようになる。

import java.io.FileOutputStream;
import java.io.BufferedOutputStream;
import java.io.OutputStream;
class Test {
  public static void main(String args) throws Exception {
    byte buf = "Hello world!\n".getBytes();
    OutputStream out = new BufferedOutputStream(new FileOutputStream("j_log.txt"));
    for(int i = 0; i < 10000000; ++i)out.write(buf);
  }
}

ではこれを、まず最適化無しで実行してみよう。

Flat profile of 8.58 secs (548 total ticks): main

  Interpreted + native   Method                        
 32.1%   176  +     0    java.io.BufferedOutputStream.write
 27.2%    22  +   127    java.lang.System.arraycopy
 13.7%    75  +     0    java.io.FilterOutputStream.write
 11.7%    64  +     0    Test.main
  9.9%     2  +    52    java.io.FileOutputStream.writeBytes
  0.4%     2  +     0    java.io.BufferedOutputStream.flushBuffer
  0.2%     1  +     0    java.util.Vector.elementAt
  0.2%     1  +     0    java.io.FileOutputStream.write
 95.3%   343  +   179    Total interpreted

  Thread-local ticks:
  0.2%     1             Class loader
  2.6%    14             Interpreter
  1.1%     6             Unknown: running frame
  0.9%     5             Unknown: thread_state


Global summary of 8.58 seconds:
100.0%   548             Received ticks
  0.2%     1             Class loader
  2.6%    14             Interpreter
  2.0%    11             Unknown code

処理終了までに約9秒しかかからなかった。バッファリング無しの場合の約半分の処理時間である。
バッファリングが無い場合だとjava.io.FileOutputStream.writeBytesに約1000ticksもかかり、それが処理全体の91%を占めていたのに対し、今回のそれはわずかに約50ticks、処理に占める割合も約10%に低下している。
代わりに、java.io.BufferedOutputStream.writeやjava.lang.System.arraycopyといったバッファリングのための処理が大きな部分を占めているが、それらを合わせても、もともとのjava.io.FileOutputStream.writeBytesにかかっていた処理負荷に比べると3分の1程度に過ぎない。


では次は、同じ処理を最適化した場合を見ることにしよう。