「ObjectOutputStream」を使用して指定された数のオブジェクトをシリアル化する単純なプログラム (以下に掲載) を考えてみましょう。オブジェクトをファイルにシリアル化するために、同じ関数を何度も呼び出します。最初の呼び出しは、後続の呼び出しよりも時間がかかります (違いは、シリアル化されるオブジェクトの数によって異なります)。
Serializing 10000 objects...
Time elapsed: 498ms
Time elapsed: 168ms
Time elapsed: 186ms
Serializing 100000 objects...
Time elapsed: 1815ms
Time elapsed: 1352ms
Time elapsed: 1338ms
Serializing 500000 objects...
Time elapsed: 8341ms
Time elapsed: 7247ms
Time elapsed: 7051ms
この違いの理由は何ですか?シリアル化せずに同じこと、つまりバイト配列を書き込もうとしましたが、そのような違いはありません。
更新:プログラムが同じメソッドを何度も呼び出すのではなく、for ループでオブジェクトをシリアル化してからメソッドを呼び出すと、同じことが起こります: 後続のメソッド呼び出しはより高速です:
"manual" serialization, time elapsed: 535
Time elapsed: 170ms
Time elapsed: 193ms
Time elapsed: 139ms
したがって、JIT コンパイルによってその違いが生じることはありません。
コード:
import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
public class SerializationTest {
static final int COUNT = 10000, TRIES = 3;
static class Simple implements Serializable {
String name;
int index;
Simple(String name, int index) {
this.name = name;
this.index = index;
}
}
public static void main(String[] args) throws IOException {
int count = COUNT;
if (args.length > 0) {
count = Integer.parseInt(args[0]);
}
List<Simple> objects = new ArrayList<Simple>();
for (int i = 0; i < count; i++) {
objects.add(new Simple("simple" + i, i));
}
String filename = args.length > 1 ? args[1] : "objects";
System.err.println("Serializing " + count + " objects...");
for(int i = 0; i < TRIES; i++) {
System.err.println("Time elapsed: " +
serializeOneByOne(objects, filename + i + ".bin", false) + "ms");
}
}
static long serializeOneByOne(List<?> objects, String filename, boolean buffered)
throws IOException {
OutputStream underlying = new FileOutputStream(filename);
if (buffered) {
underlying = new BufferedOutputStream(underlying);
}
ObjectOutputStream output = new ObjectOutputStream(underlying);
// take started after the output stream is open
// although it does not make a big difference
long started = System.currentTimeMillis();
try {
for (Object s : objects) {
output.writeObject(s);
}
} finally {
output.close();
}
long ended = System.currentTimeMillis();
return ended - started;
}
}