优化Java序列化– Java,XML,JSON,Kryo,POF

也许我很天真,但是我一直认为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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/367230.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

html5 css 字体加粗,HTML和CSS实现字体加粗的三种方法

大家在浏览网站时有没有注意到&#xff0c;页面中有些文字或字体加粗了&#xff0c;正在学习HTML和CSS的小伙伴&#xff0c;你知道HTML如何给文字加粗吗&#xff1f;CSS怎么设置字体加粗呢&#xff1f;这篇文章给大家总结了给字体和文字加粗的三种方法&#xff0c;包括HTML中的…

浅谈模拟退火

核心思想 模拟退火十分好写&#xff0c;它的核心思想就是&#xff1a; 每一次降温都可以从当前状态转移到另一种相近状态&#xff08;没有严格定义&#xff0c;可以自己想产生相近解的方法&#xff09; 如果那个相近状态的答案更优&#xff0c;当然转移到那种状态&#xff01; …

如何应用前端技术唤起app及判断用户来源及与原生交互的原理

做唤起时需要native端进行配合&#xff0c; h5唤起app这种需求是常见的。在移动为王的时代&#xff0c;h5在app导流上发挥着重要的作用。 目前我们采用的唤起方式是url scheme(iOS&#xff0c;Android平台都支持)&#xff0c;只需原生APP开发时注册scheme&#xff0c; 那么用户…

mysql 设置client char_mysql编码问题:show variables like “%char%”

mysql编码设置mysql> SHOW VARIABLES LIKE character_set_%;------------------------------------------------------| Variable_name | Value |------------------------------------------------------| character_set_client | latin1 || character_set_connection | la…

虾扯蛋之函数防抖和节流

背景 今天在coding的时候&#xff0c;做了一个搜索框&#xff0c;也正是这个搜索框&#xff0c;让我和后台小伙伴直接由铁磁变为塑料兄弟。那到底发生啥了呢&#xff1f;其实很简单&#xff0c;其实很无奈&#xff0c;就是我用王者的手速把他的接口访问崩了&#xff01; 我们在…

四川省内二本计算机公立好的大学排名,四川有哪些二本院校是公立的?附四川省公立二本大学排名及分数线...

选择科目测一测我能上哪些大学选择科目领取你的专属报告>选择省份关闭请选择科目确定v>四川省内的公办大学一直以来都是历年高考生及家长关注的重点&#xff0c;本篇文章我将针对“四川省有多少所二本公立大学&#xff1f;有哪四川省内的公办大学一直以来都是历年高考生及…

NetBeans 7.4 Beta提示警告无效的异常处理

有许多例子说明Java异常处理可能比首次出现时要困难得多&#xff0c;Josh Bloch专门将一整章的《 Effective Java》 &#xff08;两个版本&#xff09;专门用于异常处理。 Java中的检查异常模型 仍然 “ 有争议” 。 我很高兴看到我最近下载的NetBeans 7.4 beta有一些提示&…

平心静气

昨天做一个功能的时候需要修改ofbiz代码,增加关联的表和查询字段,本以为很简单,照着写一下就好了,但是一直报错.临近下班,苦思冥想没有找到原因,八点左右不得已回家了. 第二天早上半个小时搞定.关键还是要平心静气,其实只是一个大小写的问题,由于大小写不匹配,没有匹配到对应的…

mysql5.7.17解压版安装_Windows中 MySQL5.7.17解压版安装步骤

1、先去MySQL官网下载。当前最新版是5.7.19&#xff0c;可能安装方法不同了&#xff0c;本人测试没有安装成功&#xff0c;若有安装成功的朋友&#xff0c;希望分享一下安装步骤。2、将下载的压缩包解压出来&#xff0c;然后在“MySQL解压目录”中新建“data”文件夹。如下图&a…

大学计算机结课论文怎么写,大学本科计算机论文格式_大学本科计算机毕业论文范文...

导读&#xff1a;如何撰写出满意的大学本科计算机论文是现在很多人都为之苦恼的问题之一&#xff0c;而论文的撰写也并非易事&#xff0c;必定是需要花费很多心思和汗水的&#xff0c;本论文分类为大学计算机论文&#xff0c;下面是小编为大家整理的几篇大学本科计算机论文范文…

关于Java和Scala同步的五件事你不知道

实际上&#xff0c;所有服务器应用程序都需要在多个线程之间进行某种同步。 大多数同步工作是在框架级别为我们完成的&#xff0c;例如通过我们的Web服务器&#xff0c;数据库客户端或消息传递框架。 Java和Scala提供了许多组件来编写可靠的多线程应用程序。 这些包括对象池&am…

Keepalived详解之 - LVS(IPVS)管理工具ipvsadm使用指南

ipvsadm是什么? ipvsadm是用来配置、维护或者查看Linux内核当中virtual server table的一个工具, LVS(Linux virtual server)能基于一个集群当中的两个或者多个节点来创建弹性网络服务, 集群中的处于激活状态的节点能将服务请求重定向到一组实际提供服务的主机当中, 提供包括T…

精读《你不知道的javascript》中卷

前言 《你不知道的 javascript》是一个前端学习必读的系列&#xff0c;让不求甚解的JavaScript开发者迎难而上&#xff0c;深入语言内部&#xff0c;弄清楚JavaScript每一个零部件的用途。本书《你不知道的javascript》中卷介绍了该系列的两个主题&#xff1a;“类型和语法”以…

mysql触发器区分新增 修改_MySQL触发器 , 判断更新操作前后数据是否改变

改动表为user , 改动后将部分信息写入cfq_tab表1. 新增触发器create TRIGGER cfq_on_user_addafter insert on userfor each ROWBEGINinsert into cfq_tab(id,type_id,type,status) values (null,new.UID,1,0);end;2. 修改触发器 , 判断修改前后数据是否变动//DROP TRIGGER IF…

三年级计算机课画曲线,三年级上册信息技术曲线工具教案

教材分析《嬉戏山水间—曲线工具》本课教学时间一课时&#xff0c;主要内容是学习在Windows下学会画图软件中“曲线”工具的使用方法。根据教材的编排&#xff0c;本课之前&#xff0c;学生已学会了画图软件中椭圆和直线工具、多边形工具的使用&#xff0c;已经具备了画图软件的…

如何使用不同的记录器实现配置SLF4J

将slf4j库用作Java应用程序日志记录API层有很多好处。 在这里&#xff0c;我将展示一些示例&#xff0c;说明如何与不同的记录器一起使用和配置它。 您可以将slf4j视为Java接口&#xff0c;然后在运行时需要一个实现&#xff08;仅一个&#xff09;来提供实际的日志记录详细信…

Presto 学习

Presto 基础知识与概念学习可以参考这些博客&#xff1a; presto 0.166概述 https://www.cnblogs.com/sorco/p/7060166.html Presto学习-presto介绍 https://blog.csdn.net/paicMis/article/details/78516475 Presto必知必会 https://blog.csdn.net/jiangshouzhuang/article/de…

4月24号

今天老师讲了好多理论&#xff0c;首先讲了一个程序运行多次就是多个进程&#xff0c; from multiprocessing import Processimport time import osdef task(): print(%s:父进程%s%(os.getpid(),os.getppid())) time.sleep(3)if __name____main__: pProcess(targettas…

撸个微信小程序的省市区选择器

起因 微信小程序虽然已经有现成的封装好的省市区选择器给开发者使用&#xff0c;然鹅不幸的是&#xff0c;微信地址库的数据和公司用的地址库数据很难一一对上&#xff0c;那就只能撸起袖子自己写个组件了。 最终效果 思维导图 主要代码 组件 region-picker.js /* region-pic…

docker build 变量_DockerFile 设置环境变量

镜像的Layer 在docker docs里面有一句话: We’ve already seen that Docker images are read-only templates from which Docker containers are launched. Each image consists of a series of layers. Docker makes use of union file systems to combine these layers into…