考虑一个简单的程序(下面发布),它使用`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;
}
}
答案 0 :(得分:2)
完整的答案是:
ObjectOutputStream有一些内部静态缓存,用于序列化几种类型的对象(参见ObjectStreamClass),因此相同类型对象的后续序列化速度比第一个快。
< / LI>如果考虑编译ObjectOutputStream.writeObject
(而不是其他答案中提到的用户定义的方法),JIT编译可能会影响性能。感谢所有在答案中提到JIT汇编的人。
这也解释了为什么在编写字节数组而不是序列化对象时没有区别:a)没有静态缓存,而b)FileOutputStream.write(byte [])
调用本地writeBytes
,几乎没有JIT编译发生。
答案 1 :(得分:1)
在Java中,JIT(即时编译器)编译它经常调用的方法(一些建议称它为10.000次)。
但是知道java Serialization很慢并且使用了大量的内存
使用DataOutputStream序列化自己时,可以做得更好。
java内置于Serialization中,如果是快速演示项目,那就可以开箱即用。
答案 2 :(得分:1)
JVM为程序中的每个方法维护call count
。每次在程序中调用相同的方法call count
增加。只要call count
到达JIT compilation threshold
,此方法就compiled
JIT
{{1}}。并且下次调用此方法时,其执行速度更快,因为现在解释方法解释器正在执行本机代码。因此,相同方法的第一次调用比后续调用花费更多时间。
答案 3 :(得分:0)
第一次运行它时会产生很多成本,JIT编译,类加载,反射等等。这是正常的,大多数时候都不用担心,因为生产应用程序中的影响是可以忽略不计。