我有一个Java程序,它在内存中将数据准备成相当复杂的大数据结构(几GB),并将其序列化到磁盘,另一个程序在内存中读回序列化的数据结构。我惊讶地注意到反序列化步骤相当慢,而且它是受CPU限制的。( top中的CPU使用率为100%,但iotop的读取速度仅为3到5 MB/s,对于硬盘驱动器上的顺序读取而言,这是非常低的)。CPU相当新(Core i7-3820),结构适合内存,没有配置交换空间。
为何会这样呢?有没有其他方法可以在Java中序列化对象,而不是将CPU作为瓶颈?
以下是反序列化代码,以防万一:
FileInputStream f = new FileInputStream(path);
ObjectInputStream of = new ObjectInputStream(f);
Object obj = of.readObject();发布于 2012-04-10 23:34:56
反序列化是非常昂贵的。如果你使用泛型反序列化,它将使用大量的反射和创建对象。
有很多更快的选择,而且大多数都使用生成的代码而不是反射。
http://code.google.com/p/thrift-protobuf-compare/wiki/Benchmarking
您会注意到,最快的方法之一是使用Externalizable,这可能是您的一个选择。这意味着为对象的序列化和反序列化添加自定义方法。
我已经编写了更快的方法,但这避免了通过回收它们或就地使用文件中的数据来创建任何对象(即不需要反序列化它们)
发布于 2012-04-10 23:35:51
如果不使用分析器查看,或者不了解对象结构的实际层次结构,就很难说出这一点,但我假设,如果它“相当复杂”,并且大约“几GB”大,那么您可能正在处理数千个单独的对象。
我最好的猜测是,Java反射会扼杀您的性能。反射用于从流构造对象,众所周知,这至少比直接在代码中调用构造函数慢两个数量级。因此,如果您的对象有大量的“小”对象,反射将花费大量时间重新构建它们。
您可以尝试的一件事(如果您还没有尝试过)是在每个Serializable类的顶部声明以下行:
private static final long serialVersionUID = [some number]L;如果不声明这个ID,Java将不得不计算它,因此可以通过声明它来节省一些CPU周期。
如需进一步参考:
https://stackoverflow.com/questions/10091505
复制相似问题