也许我很天真,但是我一直认为Java序列化肯定是将Java对象序列化为二进制形式的最快,最有效的方法。 毕竟Java是第7个主要发行版,所以这不是新技术,并且由于每个JDK似乎都比上一个快,因此我错误地认为序列化现在必须非常快速和高效。 我认为,由于Java序列化是二进制的,并且依赖于语言,因此它必须比XML或JSON更快,更高效。 不幸的是,我错了,如果您担心性能,建议不要使用Java序列化。

现在,请不要误会我的意思,我不是在尝试破坏Java。 Java序列化有许多要求,主要的需求是能够将任何东西(或至少任何实现Serializable东西) Serializable到任何其他JVM(甚至是不同的JVM版本/实现)中,甚至运行被序列化的类的不同版本(例如只要您设置了serialVersionUID )。 最主要的是,它确实有效,而且确实很棒。 性能不是主要要求,格式是标准的并且必须向后兼容,因此优化非常困难。 而且,对于许多类型的用例,Java序列化执行得很好。

在研究三层并发基准时,我开始了进入序列化过程的旅程。 我注意到Java序列化过程中花费了大量CPU时间,因此我决定进行调查。 我从序列化具有几个字段的简单Order对象开始。 我序列化了对象并输出了字节。 尽管Order对象只有几个字节的数据,但我并不是天真地认为它将序列化为几个字节,但我对序列化足够了解,因此至少需要写出完整的类名,因此它知道它已序列化的内容,因此可以将其读回。 因此,我期望大约50个字节。 结果超过了600个字节,那时候我意识到Java序列化并不像我想象的那么简单。

Order对象的Java序列化字节

----sr--model.Order----h#-----J--idL--customert--Lmodel/Customer;L--descriptiont--Ljava/lang/String;L--orderLinest--Ljava/util/List;L--totalCostt--Ljava/math/BigDecimal;xp--------ppsr--java.util.ArrayListx-----a----I--sizexp----w-----sr--model.OrderLine--&-1-S----I--lineNumberL--costq-~--L--descriptionq-~--L--ordert--Lmodel/Order;xp----sr--java.math.BigDecimalT--W--(O---I--scaleL--intValt--Ljava/math/BigInteger;xr--java.lang.Number-----------xp----sr--java.math.BigInteger-----;-----I--bitCountI--bitLengthI--firstNonzeroByteNumI--lowestSetBitI--signum[--magnitudet--[Bxq-~----------------------ur--[B------T----xp----xxpq-~--xq-~--

(注意“-”表示不可打印的字符)

您可能已经注意到,Java序列化不仅写出要序列化的对象的完整类名,而且还写出要序列化的类的整个类定义以及所有引用的类。 类定义可能非常大,并且似乎是主要的性能和效率问题,尤其是在编写单个对象时。 如果要写出大量相同类的对象,则类定义开销通常不是大问题。 我注意到的另一件事是,如果您的对象具有对类的引用(例如元数据对象),则Java序列化将编写整个类定义,而不仅仅是类名,因此使用Java序列化来编写元数据非常昂贵。

可外部化

通过实现Externalizable接口可以优化Java序列化。 实现此接口可以避免写出整个类定义,而只需编写类名即可。 它要求您实现readExternalwriteExternal方法,因此需要您进行一些工作和维护,但是比仅实现Serializable更快,更高效。

关于Externalizable结果的一个有趣注释是,对于少量对象,它的效率要高得多,但对于大量对象,实际上输出的字节数要比Serializable多。 我假设Externalizable格式对重复对象的效率稍低。

可外部化的类

public class Order implements Externalizable {private long id;private String description;private BigDecimal totalCost = BigDecimal.valueOf(0);private List orderLines = new ArrayList();private Customer customer;public Order() {}public void readExternal(ObjectInput stream) throws IOException, ClassNotFoundException {this.id = stream.readLong();this.description = (String)stream.readObject();this.totalCost = (BigDecimal)stream.readObject();this.customer = (Customer)stream.readObject();this.orderLines = (List)stream.readObject();}public void writeExternal(ObjectOutput stream) throws IOException {stream.writeLong(this.id);stream.writeObject(this.description);stream.writeObject(this.totalCost);stream.writeObject(this.customer);stream.writeObject(this.orderLines);}
}

Order对象的可外部化的序列化字节

----sr--model.Order---*3--^---xpw---------psr--java.math.BigDecimalT--W--(O---I--scaleL--intValt--Ljava/math/BigInteger;xr--java.lang.Number-----------xp----sr--java.math.BigInteger-----;-----I--bitCountI--bitLengthI--firstNonzeroByteNumI--lowestSetBitI--signum[--magnitudet--[Bxq-~----------------------ur--[B------T----xp----xxpsr--java.util.ArrayListx-----a----I--sizexp----w-----sr--model.OrderLine-!!|---S---xpw-----pq-~--q-~--xxx

其他序列化选项

我开始研究Java中还有哪些其他序列化选项。 我从EclipseLink MOXy开始,它支持通过JAXB API将对象序列化为XML或JSON。 我并不期望XML序列化能胜过Java序列化,因此在某些用例中确实感到惊讶。 我还找到了产品Kryo,这是一个用于优化序列化的开源项目。 我还研究了Oracle Coherence POF序列化格式。 每个产品都有优点和缺点,但我的主要重点是比较它们的性能和效率。

EclipseLink MOXy – XML和JSON

使用EclipseLink MOXy序列化为XML或JSON的主要优点是两者都是标准的可移植格式。 您可以使用任何语言从任何客户端访问数据,因此与Java序列化一样,不限于Java。 您还可以将数据与Web服务和REST服务集成。 两种格式都基于文本,因此易于阅读。 不需要编码或特殊接口,只需元数据。 性能是完全可以接受的,并且对于小型数据集,其性能优于Java序列化。

缺点是文本格式的效率不如优化的二进制格式,并且JAXB需要元数据。 因此,您需要使用JAXB批注来批注您的类,或提供一个XML配置文件。 另外,默认情况下不处理循环引用,您需要使用@XmlIDREF来处理循环。

JAXB注释的类

@XmlRootElement
public class Order {@XmlID@XmlAttributeprivate long id;@XmlAttributeprivate String description;@XmlAttributeprivate BigDecimal totalCost = BigDecimal.valueOf(0);private List orderLines = new ArrayList();private Customer customer;
}public class OrderLine {@XmlIDREFprivate Order order;@XmlAttributeprivate int lineNumber;@XmlAttributeprivate String description;@XmlAttributeprivate BigDecimal cost = BigDecimal.valueOf(0);
}

订单对象的EclipseLink MOXy序列化XML

<order id="0" totalCost="0"><orderLines lineNumber="1" cost="0"><order>0</order></orderLines></order>

订单对象的EclipseLink MOXy序列化JSON

{"order":{"id":0,"totalCost":0,"orderLines":[{"lineNumber":1,"cost":0,"order":0}]}}

ry

Kryo是一个快速,高效的Java序列化框架。 Kryo是根据New BSD许可提供的Google代码上的开源项目。 这是一个很小的项目,只有3个成员,它于2009年首次发布,最后一次于2013年2月发布2.21版本,因此仍在积极开发中。

Kryo的工作方式类似于Java序列化,并且尊重瞬态字段,但不需要类可序列化。 我发现Kryo有一些限制,例如要求类具有默认构造函数,并且在序列化java.sql.Time,java.sql.Date和java.sql.Timestamp类时遇到了一些问题。

Order对象的Kryo序列化字节

------java-util-ArrayLis-----model-OrderLin----java-math-BigDecima---------model-Orde-----

Oracle Coherence POF

Oracle Coherence产品提供了自己优化的二进制格式,称为POF(便携式对象格式)。 Oracle Coherence是一种内存数据网格解决方案(分布式缓存)。 一致性是一种商业产品,需要许可证。 EclipseLink通过使用Coherence作为EclipseLink共享缓存的Oracle TopLink Grid产品支持与Oracle Coherence的集成。

POF提供了序列化框架,并且可以独立于Coherence使用(如果您已经获得Coherence许可)。 POF要求您的类实现可PortableObject接口和读/写方法。 您还可以实现单独的Serializer类,或在最新的Coherence版本中使用注释。 POF要求为每个类提前分配一个常量ID,因此您需要某种方式确定此ID。 POF格式是一种二进制格式,非常紧凑,高效且快速,但是您需要做一些工作。

POF的总字节数对于单个Order / OrderLine对象为32字节,对于100 OrderLines为1593字节。 我不会给出结果,因为POF是一种商业许可产品的一部分,但是速度非常快。

POF便携式对象

public class Order implements PortableObject {private long id;private String description;private BigDecimal totalCost = BigDecimal.valueOf(0);private List orderLines = new ArrayList();private Customer customer;public Order() {}public void readExternal(PofReader in) throws IOException {this.id = in.readLong(0);this.description = in.readString(1);this.totalCost = in.readBigDecimal(2);this.customer = (Customer)in.readObject(3);this.orderLines = (List)in.readCollection(4, new ArrayList());}public void writeExternal(PofWriter out) throws IOException {out.writeLong(0, this.id);out.writeString(1, this.description);out.writeBigDecimal(2, this.totalCost);out.writeObject(3, this.customer);out.writeCollection(4, this.orderLines);}
}

Order对象的POF序列化字节

-----B--G---d-U------A--G-------

结果

那么每种表现如何呢? 我做了一个简单的基准比较不同的序列化机制。 我比较了两个不同用例的序列化。 第一个是具有单个OrderLine对象的单个Order对象。 第二个是具有100个OrderLine对象的单个Order对象。 我比较了每秒的平均序列化操作,并测量了序列化数据的字节大小。 不同的对象模型,用例和环境将产生不同的结果,但这使您对不同的序列化器的性能差异有一个大致的了解。

结果表明,Java序列化对于少量对象来说很慢,但是对于大量对象来说很好。 相反,对于少量对象,XML和JSON的性能优于Java序列化,但是对于大量对象,Java序列化的速度更快。 Kryo和其他优化的二进制序列化程序在这两种数据类型方面均优于Java序列化。

您可能想知道,为什么不到一毫秒的时间与性能有任何关系,这可能是相关的,您可能是对的。 通常,如果您写出大量对象,然后Java序列化执行得很好,那么您只会遇到一个实际的性能问题,那么,对于少量对象而言,它的执行效果很差吗? 对于单个操作,这可能是正确的,但是如果执行许多小的序列化操作,则成本相关的。 为许多客户端提供服务的典型服务器通常会发出许多小请求,因此尽管序列化的成本不足以使这些单个请求中的任何一个花费很长时间,但它将极大地影响服务器的可伸缩性。

用1条订单行订购

序列化器 大小(字节) 序列化(操作/秒) 反序列化(操作数/秒) 差异百分比(来自Java序列化) 差异百分比(反序列化)
Java可序列化 636 128,634 19,180 0% 0%
Java可外部化 435 160,549 26,678 24% 39%
EclipseLink MOXy XML 101 348,056 47,334 170% 146%
ry 90 359,368 346,984 179% 1709%

订购100条订单行

序列化器 大小(字节) 序列化(操作/秒) 反序列化(操作数/秒) 差异百分比(来自Java序列化) 差异百分比(反序列化)
Java可序列化 2,715 16,470 10,215 0% 0%
Java可外部化 2,811 16,206 11,483 -1% 12%
EclipseLink MOXy XML 6,628 7,304 2,731 -55% -73%
ry 1216 22862 31,499 38% 208%

EclipseLink JPA

在EclipseLink 2.6开发版本(在某种程度上为2.5)中,我们增加了在EclipseLink进行序列化的任何地方选择序列化程序的功能。

这样的地方之一是序列化@Lob映射。 现在,您可以使用@Convert批注指定序列化程序,例如@Convert(XML),@ Convert(JSON),@ Convert(Kryo)。 除了优化性能之外,这还提供了一种简单的机制来将XML和JSON数据写入数据库。

同样对于EclipseLink缓存协调,您可以使用“ eclipselink.cache.coordination.serializer”属性选择序列化器。

这篇文章中使用的基准测试的源代码可以在这里找到,或者在这里下载。

参考: 优化Java序列化– Java Persistence Performance博客上的JCG合作伙伴 James Sutherland提供的Java vs XML vs JSON vs Kryo vs POF 。

翻译自: https://www.javacodegeeks.com/2013/09/optimizing-java-serialization-java-vs-xml-vs-json-vs-kryo-vs-pof.html

优化Java序列化– Java,XML,JSON,Kryo,POF相关推荐

  1. kryo java_优化Java序列化– Java,XML,JSON,Kryo,POF

    kryo java 也许我很天真,但是我一直认为Java序列化肯定是将Java对象序列化为二进制形式的最快,最有效的方法. 毕竟Java是第7个主要发行版,所以这不是新技术,而且由于每个JDK似乎都比 ...

  2. SpringMVC中使用@RequestBody,@ResponseBody注解实现Java对象和XML/JSON数据自动转换)

    Spring3.1开始使用新的HandlerMapping 和 HandlerAdapter 来支持@Contoller 和@RequestMapping注解处理:处理器映射RequestMappin ...

  3. Java 序列化对象为json字符串,属性首字母大写,并按照属性首字母排序

    1.创建类 import lombok.Data; import lombok.NoArgsConstructor; import lombok.AllArgsConstructor;import c ...

  4. krait和kryo_各种Java序列化性能比较

    并发主题 各种Java序列化性能比较 这里比较Java对象序列化 XML JSON Kryo POF等序列化性能比较. 很多人以为JDK的Java序列化肯定是将Java对象转换成二进制序列化最快的方式 ...

  5. Java序列化案例demo(包含Kryo、JDK原生、Protobuf、ProtoStuff以及hessian)

    文章目录 前言 一.Kryo序列化(优先选择) 介绍 快速开始 测试 二.JDK原生序列化 介绍 快速开始 测试 三.Protobuf序列化 介绍 快速开始 测试 四.ProtoStuff 介绍 快速 ...

  6. 20180826(04)-Java序列化

    Java序列化 Java 提供了一种对象序列化的机制,该机制中,一个对象可以被表示为一个字节序列, 该字节序列包括该对象的数据.有关对象的类型的信息和存储在对象中数据的类型 将序列化对象写入文件之后, ...

  7. JAVA序列化标准格式(XML、JSON)

    (一) 序列化:将java对象转换为字节序列的过程叫做序列化 反序列化:将字节对象转换为java对象的过程叫做反序列化 通常情况下,序列化有两种用途: 1) 把对象的字节序列永久的保存在硬盘中 2) ...

  8. 序列化: 一个老家伙的咸鱼翻身(Java对象、XML、JSON、反序列化)

    转自:码农翻身(微信号:coderising) 1.寒冬的蛰伏 这里的工作很繁忙,一年365天, 一天24小时几乎不停工. 但是我却是一个闲人, 因为我做的工作最近用的人太少了, 经常被冷落在一边. ...

  9. 在Dubbo中使用高效的Java序列化(Kryo和FST)

    作者:沈理 文档版权: Apache 2.0许可证 署名-禁止演绎 完善中-- TODO 生成可点击的目录 目录 序列化漫谈 启用Kryo和FST 注册被序列化类 无参构造函数和Serializabl ...

最新文章

  1. 提高C++性能的编程技术笔记:总结
  2. 二叉树-二叉树的最大深度(递归 )
  3. UA MATH523A 实分析1 度量空间 概念与定理总结
  4. python selenium定位元素方法,python + selenium 练习篇 - 定位元素的方法
  5. 图像锐化处理算法matlab,图像锐化matlab算法
  6. java store()_Java.util.Properties.store()
  7. 力扣236. 二叉树的最近公共祖先(JavaScript)
  8. 零基础学习编程大概需要多久?
  9. TDengine 在IT运维监控领域的应用
  10. NOT EXISTS真的不走索引么?如何优化NOT EXISTS!
  11. 昨天我请教了几位大佬,他们告诉我要这样学习编程!
  12. MATLAB中CVX工具箱解决凸优化问题的基本知识——语法、变量声明、目标函数、约束条件、cvx编程错误及解决方法
  13. ip (internet protocol)
  14. Linux中如何启动redis服务
  15. AI开发过程中常用开发命令及软件安装
  16. 邮件协议rfc822文档
  17. gitkraken免费版本6.5.1,Linux下载地址
  18. 中心性(centrality)
  19. alarm()闹钟函数
  20. 第14节 CentOS7虚拟机安装及界面图形化

热门文章

  1. 尚硅谷2020最新版SpringCloud(H版alibaba)框架开发教程全套完整版从入门到精通
  2. 10人以下小团队管理手册-学习笔记
  3. 分类器评估参数——准确度和精度的区别(足球荔枝)
  4. 《线性代数及其应用》
  5. annotations_Spring Annotations我从来没有机会使用第2部分:@ConfigurationProperties
  6. dp括号匹配 网易面试题_面试题:大括号验证
  7. spring集成mq_使用Spring Integration Java DSL与Rabbit MQ集成
  8. 工厂模式理解_工厂模式
  9. lucene_Lucene组件概述
  10. java文章上一篇下一篇_每个人都必须阅读的10篇Java文章