Java中第一次尝试序列化的速度慢吗?
考虑一个简单的程序(发布在下面),它使用“ObjectOutputStream”序列化给定数量的对象。它多次调用同一函数将对象序列化到文件。第一次调用比后续调用花费的时间更长(差异取决于被序列化的对象的数量): 造成这种差异的原因是什么?我尝试在没有序列化的情况下做同样的事情,即编写一个字节数组,但没有这样的区别 更新:如果程序不多次调用同一方法,而是在for循环中序列化对象,然后调用该方法,则会发生同样的情况:后续的方法调用速度更快:Java中第一次尝试序列化的速度慢吗?,java,serialization,io,Java,Serialization,Io,考虑一个简单的程序(发布在下面),它使用“ObjectOutputStream”序列化给定数量的对象。它多次调用同一函数将对象序列化到文件。第一次调用比后续调用花费的时间更长(差异取决于被序列化的对象的数量): 造成这种差异的原因是什么?我尝试在没有序列化的情况下做同样的事情,即编写一个字节数组,但没有这样的区别 更新:如果程序不多次调用同一方法,而是在for循环中序列化对象,然后调用该方法,则会发生同样的情况:后续的方法调用速度更快: "manual" serialization, time
"manual" serialization, time elapsed: 535
Time elapsed: 170ms
Time elapsed: 193ms
Time elapsed: 139ms
因此,JIT编译不会导致这种差异
代码:
import java.io.BufferedOutputStream;
导入java.io.FileOutputStream;
导入java.io.IOException;
导入java.io.ObjectOutputStream;
导入java.io.OutputStream;
导入java.io.Serializable;
导入java.util.ArrayList;
导入java.util.List;
公共类序列化测试{
静态最终整数计数=10000,尝试次数=3;
静态类Simple实现可序列化{
字符串名;
整数指数;
简单(字符串名,整数索引){
this.name=名称;
这个指数=指数;
}
}
公共静态void main(字符串[]args)引发IOException{
int count=计数;
如果(args.length>0){
count=Integer.parseInt(args[0]);
}
列表对象=新的ArrayList();
for(int i=0;i1?args[1]:“对象”;
System.err.println(“序列化”+count+“对象…”);
for(int i=0;i
您在第一次运行它时会产生大量成本,包括JIT编译、类加载、反射等。这是正常的,而且大多数情况下无需担心,因为对生产应用程序的影响可以忽略不计 您在第一次运行时就要付出大量的成本,包括JIT编译、类加载、反射等。这是正常的,大多数情况下不需要担心,因为对生产应用程序的影响可以忽略不计 在Java中,JIT(即时编译器)在经常调用某个方法时进行编译(有些建议调用10.000次)。但是众所周知,java序列化速度慢,并且占用大量内存。
当您使用DataOutputStream序列化自己时,您可以做得更好。
java内置串行化,如果用于快速演示项目,则可以立即消除bug。在java中,JIT(即时编译器)在经常调用方法时进行编译(有些建议调用10.000次)。
但是众所周知,java序列化速度慢,并且占用大量内存。
当您使用DataOutputStream序列化自己时,您可以做得更好。
java内置串行化,如果用于快速演示项目,则可以立即消除bug。JVM为程序中的每个方法维护一个
调用计数。每次在程序中调用相同的方法,其调用计数都会增加。一旦其调用计数
达到JIT编译阈值
,此方法就由JIT
编译。下一次调用这个方法时,它的执行会更快,因为解释器现在不是解释方法而是执行本机代码。因此,同一方法的第一次调用比随后的调用花费更多的时间。JVM为程序中的每个方法维护一个调用计数。每次在程序中调用同一方法,其调用计数都会增加。一旦其调用计数
达到JIT编译阈值
,此方法就由JIT
编译。下一次调用这个方法时,它的执行会更快,因为解释器现在不是解释方法而是执行本机代码。因此,同一方法的第一次调用比后续调用花费更多的时间。完整的答案是:
ObjectOutputStream对于正在序列化的几种类型的对象具有一些内部静态缓存(请参阅),因此相同类型对象的后续序列化速度比第一种快
如果考虑编译ObjectOutputStream.writeObject
(而不是其他答案中提到的用户定义方法),JIT编译可能会影响性能。感谢所有在回答中提到JIT编译的人
这也解释了为什么在编写字节数组而不是序列化对象时没有区别:a)没有静态缓存和b)FileOutputStream.write(byte[])
调用本机writeBytes
,几乎不进行JIT编译。完整的答案是:
对象输出树
"manual" serialization, time elapsed: 535
Time elapsed: 170ms
Time elapsed: 193ms
Time elapsed: 139ms
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;
}
}