【问题标题】:Why is Java deserialization CPU-bound?为什么 Java 反序列化受 CPU 限制?
【发布时间】:2012-04-10 15:18:17
【问题描述】:

我有一个 Java 程序,它将数据准备成内存中相当复杂和大的数据结构(几 GB)并将其序列化到磁盘,以及另一个程序读取内存中的序列化数据结构。我惊讶地注意到反序列化步骤非常慢,而且它受 CPU 限制。 (top 中的 CPU 使用率为 100%,但使用iotop 读取的速度仅为 3 到 5 MB/s,这对于硬盘驱动器上的顺序读取来说非常低)。 CPU 相当新(Core i7-3820),结构适合内存,未配置交换空间。

为什么会这样?是否有另一种方法可以在没有 CPU 瓶颈的 Java 中序列化对象?

这是反序列化代码,以防万一:

FileInputStream f = new FileInputStream(path);
ObjectInputStream of = new ObjectInputStream(f);
Object obj = of.readObject();

【问题讨论】:

  • IIRC 它使用的反射魔法可与 .NET 序列化程序的工作方式相媲美。那很慢。有一种概念上简单但“大量输入”的方法可以避免所有这些 - 手动完成。也就是说,逐个字段递归地将对象写入二进制流。加载则相反。
  • 这可能会有所帮助:vanillajava.blogspot.co.uk/2011/10/…
  • 你可以尝试用BufferedInputStream 包裹FileInputStream 吗?

标签: java performance serialization deserialization


【解决方案1】:

反序列化非常昂贵。如果你使用泛型反序列化,它会使用大量的反射和对象的创建。

有很多替代方法更快,并且大多数使用生成的代码而不是反射。

http://code.google.com/p/thrift-protobuf-compare/wiki/Benchmarking

您会注意到,最快的方法之一是使用 Externalizable,这可能是您的一个选择。这意味着为对象的序列化和反序列化添加自定义方法。

我已经编写了最快的方法,但这避免了通过回收它们或就地使用文件中的数据来创建任何对象(即无需反序列化它们)

【讨论】:

    【解决方案2】:

    如果不使用分析器查看此内容或对对象结构的实际层次结构了解很多,很难说,但我假设如果它“相当复杂”并且在“几 GB”大的数量级上,您'可能正在处理数千个单独的对象。

    我最好的猜测是 Java 反射正在扼杀你的性能。反射用于从您的流中构造对象,已知它比直接在代码中调用构造函数慢至少两个数量级。因此,如果您的对象有大量“小”对象,Reflection 将花费大量时间来重建它们。

    您可以尝试的一件事(如果您还没有尝试的话)是在每个 Serializable 类的顶部声明以下行:

    private static final long serialVersionUID = [some number]L;
    

    如果您不声明此 ID,Java 将不得不计算它,因此您确实可以通过声明它来节省一些 CPU 周期。

    进一步参考:

    http://oreilly.com/catalog/javarmi/chapter/ch10.html

    【讨论】:

      猜你喜欢
      • 2014-05-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-04
      • 1970-01-01
      • 2023-03-13
      相关资源
      最近更新 更多