一、概述
在很多论坛上都会谈论Java序列化,到底哪个很好呢?各有各的观点。这几天晚上正好在研究淘宝的dubbo的源代码,看到它写的一个测试用例,工程下载见:
http://code.alibabatech.com/svn/dubbo/trunk/dubbo-common
二、测试分析
对同一个对象进行序列化:对象为long[] data = new long[] { -1l, 2l, 3l, 4l, 5l };
java:aced0005757200025b4a782004b512b17593020000787000000005ffffffffffffffff0000000000000002000000000000000300000000000000040000000000000005:67
compacted java:aced000575720000025b4a782004b512b17593020000787000000005ffffffffffffffff0000000000000002000000000000000300000000000000040000000000000005:68
hessian:75055b6c6f6e67dfe2e3e4e5:12
Dubbo:8585181b1c1d1e:7
说明:对于小数据的序列化,Dubbo生成的字节是最小的,只有7个,而Java,Compacted Java是最大
,分别有67个和68个,序列化的结果越小,越适合rpc服务调用
对同一个对象连续进行500次Write和Parse
Dubbo:write and parse 500 times in 62ms, size 212
Hessian2: write and parse 500 times in 516ms, size 378
Java: write and parse 500 times in 203ms, size 969
compacted java: write and parse 500 times in 109ms, size 596
说明:和第一种的测试情况类似,dubbo的性能是最好的,花费的时间只共只有62ms,而大小只有212byte
对一个超大对象进行一次的的Write和parse,如果细分的话,大概有100w个元素
[reportprint]Dubbo write 1 times in 734ms, size 9600316
[reportprint]Dubbo parse 1 times in 734ms, size 9600316
[reportprint]Hessian2 write 1 times in 328ms, size 4100479
[reportprint]Hessian2 parse 1 times in 563ms, size 4100479
[reportprint]java write 1 times in 219ms, size 6800896
[reportprint]java parse 1 times in 172ms, size 6800896
[reportprint]compacted java write 1 times in 188ms, size 6800474
[reportprint] compacted java write and parse 1 times in 234ms, size 6800474
说明:对于超大的数据,jdk自带的序列化性能最好,其次compacted java,Dubbo反而最差.
三、测试代码
/* * Copyright 1999-2011 Alibaba Group. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.alibaba.dubbo.common.serialize; import static org.junit.Assert.assertEquals; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; import org.junit.Test; import com.alibaba.com.caucho.hessian.io.Hessian2Input; import com.alibaba.com.caucho.hessian.io.Hessian2Output; import com.alibaba.dubbo.common.io.Bytes; import com.alibaba.dubbo.common.serialize.support.dubbo.Builder; import com.alibaba.dubbo.common.serialize.support.java.CompactedObjectInputStream; import com.alibaba.dubbo.common.serialize.support.java.CompactedObjectOutputStream; /** * @author qian.lei * @author ding.lid */ public class SerializationCompareTest { public void addBand(Band band, int loop) { for (int i = 0; i < loop; i++) { DataElement p = new DataElement(); p.setField("adafadsfasf"); p.setTitle("afdasf"); band.addChild(p); } } public ReportPrint getReportPrint() { int loop = 1000; ReportPrint config = new ReportPrint(); addBand(config.getHeader(), 1); addBand(config.getPageHeader(), 1); addBand(config.getDetail(), loop * 100);// 有100行明细 addBand(config.getFooter(), 1); return config; } @Test public void test_CompareSerializeLength() throws Exception { long[] data = new long[] { -1l, 2l, 3l, 4l, 5l }; ByteArrayOutputStream os; os = new ByteArrayOutputStream(); ObjectOutputStream jos = new ObjectOutputStream(os); jos.writeObject(data); System.out.println("java:" + Bytes.bytes2hex(os.toByteArray()) + ":" + os.size()); os = new ByteArrayOutputStream(); CompactedObjectOutputStream oos = new CompactedObjectOutputStream(os); oos.writeObject(data); System.out.println("compacted java:" + Bytes.bytes2hex(os.toByteArray()) + ":" + os.size()); os = new ByteArrayOutputStream(); Hessian2Output h2o = new Hessian2Output(os); h2o.writeObject(data); h2o.flushBuffer(); System.out.println("hessian:" + Bytes.bytes2hex(os.toByteArray()) + ":" + os.size()); os = new ByteArrayOutputStream(); Builder<long[]> lb = Builder.register(long[].class); lb.writeTo(data, os); System.out.println("DataOutput:" + Bytes.bytes2hex(os.toByteArray()) + ":" + os.size()); } @Test public void testBuilderPerm() throws Exception { Builder<Bean> bb = Builder.register(Bean.class); Bean bean = new Bean(); int len = 0; long now = System.currentTimeMillis(); for (int i = 0; i < 500; i++) { ByteArrayOutputStream os = new ByteArrayOutputStream(); bb.writeTo(bean, os); os.close(); if (i == 0) len = os.toByteArray().length; ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray()); Bean b = bb.parseFrom(is); assertEquals(b.getClass(), Bean.class); } System.out.println("Builder write and parse 500 times in " + (System.currentTimeMillis() - now) + "ms, size " + len); } @Test public void testH2oPerm() throws Exception { Bean bean = new Bean(); int len = 0; long now = System.currentTimeMillis(); for (int i = 0; i < 500; i++) { ByteArrayOutputStream os = new ByteArrayOutputStream(); Hessian2Output out = new Hessian2Output(os); out.writeObject(bean); out.flushBuffer(); os.close(); if (i == 0) len = os.toByteArray().length; ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray()); Hessian2Input in = new Hessian2Input(is); assertEquals(in.readObject().getClass(), Bean.class); } System.out.println("Hessian2 write and parse 500 times in " + (System.currentTimeMillis() - now) + "ms, size " + len); } @Test public void testJavaOutputPerm() throws Exception { Bean bean = new Bean(); int len = 0; long now = System.currentTimeMillis(); for (int i = 0; i < 500; i++) { ByteArrayOutputStream os = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(os); out.writeObject(bean); os.close(); if (i == 0) len = os.toByteArray().length; ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray()); ObjectInputStream in = new ObjectInputStream(is); assertEquals(in.readObject().getClass(), Bean.class); } System.out.println("java write and parse 500 times in " + (System.currentTimeMillis() - now) + "ms, size " + len); } @Test public void testCompactedJavaOutputPerm() throws Exception { Bean bean = new Bean(); int len = 0; long now = System.currentTimeMillis(); for (int i = 0; i < 500; i++) { ByteArrayOutputStream os = new ByteArrayOutputStream(); CompactedObjectOutputStream out = new CompactedObjectOutputStream( os); out.writeObject(bean); os.close(); if (i == 0) len = os.toByteArray().length; ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray()); CompactedObjectInputStream in = new CompactedObjectInputStream(is); assertEquals(in.readObject().getClass(), Bean.class); } System.out.println("compacted java write and parse 500 times in " + (System.currentTimeMillis() - now) + "ms, size " + len); } @Test public void testBuilderPerm1() throws Exception { Builder<ReportPrint> bb = Builder.register(ReportPrint.class); ReportPrint bean = this.getReportPrint(); int len = 0; long now = System.currentTimeMillis(); ByteArrayOutputStream os = new ByteArrayOutputStream(); bb.writeTo(bean, os); os.close(); len = os.toByteArray().length; System.out.println("[reportprint]Builder write 1 times in " + (System.currentTimeMillis() - now) + "ms, size " + len); now = System.currentTimeMillis(); ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray()); ReportPrint b = bb.parseFrom(is); assertEquals(b.getClass(), ReportPrint.class); System.out.println("[reportprint]Builder parse 1 times in " + (System.currentTimeMillis() - now) + "ms, size " + len); } @Test public void testH2oPerm1() throws Exception { ReportPrint bean = this.getReportPrint(); long now = System.currentTimeMillis(); ByteArrayOutputStream os = new ByteArrayOutputStream(); Hessian2Output out = new Hessian2Output(os); out.writeObject(bean); out.flushBuffer(); int len = os.toByteArray().length; os.close(); System.out.println("[reportprint]Hessian2 write 1 times in " + (System.currentTimeMillis() - now) + "ms, size " + len); now = System.currentTimeMillis(); ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray()); Hessian2Input in = new Hessian2Input(is); assertEquals(in.readObject().getClass(), ReportPrint.class); System.out.println("[reportprint]Hessian2 parse 1 times in " + (System.currentTimeMillis() - now) + "ms, size " + len); } @Test public void testJavaOutputPerm1() throws Exception { ReportPrint bean = this.getReportPrint(); long now = System.currentTimeMillis(); ByteArrayOutputStream os = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(os); out.writeObject(bean); int len = os.toByteArray().length; os.close(); System.out.println("[reportprint]java write 1 times in " + (System.currentTimeMillis() - now) + "ms, size " + len); now = System.currentTimeMillis(); ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray()); ObjectInputStream in = new ObjectInputStream(is); assertEquals(in.readObject().getClass(), ReportPrint.class); System.out.println("[reportprint]java parse 1 times in " + (System.currentTimeMillis() - now) + "ms, size " + len); } @Test public void testCompactedJavaOutputPerm1() throws Exception { ReportPrint bean = this.getReportPrint(); long now = System.currentTimeMillis(); ByteArrayOutputStream os = new ByteArrayOutputStream(); CompactedObjectOutputStream out = new CompactedObjectOutputStream(os); out.writeObject(bean); int len = os.toByteArray().length; os.close(); System.out.println("[reportprint]compacted write 1 times in " + (System.currentTimeMillis() - now) + "ms, size " + len); now = System.currentTimeMillis(); ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray()); CompactedObjectInputStream in = new CompactedObjectInputStream(is); assertEquals(in.readObject().getClass(), ReportPrint.class); System.out .println("[reportprint]compacted write and parse 1 times in " + (System.currentTimeMillis() - now) + "ms, size " + len); } public static enum EnumTest { READ, WRITE, CREATE, UNREGISTER }; static class MyList<T> extends ArrayList<T> { private static final long serialVersionUID = 1L; private int code = 12345; private String id = "feedback"; } static class MyMap<K, V> extends HashMap<K, V> { private static final long serialVersionUID = 1L; private int code = 12345; private String id = "feedback"; } public static class Bean implements Serializable { private static final long serialVersionUID = 7737610585231102146L; public EnumTest ve = EnumTest.CREATE; public int vi = 0; public long vl = 100l; boolean b = true; boolean[] bs = { false, true }; String s1 = "1234567890"; String s2 = "1234567890一二三四五六七八九零"; int i = 123123, ni = -12344, is[] = { 1, 2, 3, 4, -1, -2, -3, -4 }; short s = 12, ns = -76; double d = 12.345, nd = -12.345; long l = 1281447759383l, nl = -13445l; private ArrayList<Object> mylist = new ArrayList<Object>(); { mylist.add(1); mylist.add("qianlei"); mylist.add("qianlei"); mylist.add("qianlei"); mylist.add("qianlei"); } private HashMap<Object, Object> mymap = new HashMap<Object, Object>(); { mymap.put(1, 2); mymap.put(2, "1234"); mymap.put("2345", 12938.122); mymap.put("2345", -1); mymap.put("2345", -1.20); } public ArrayList<Object> getMylist() { return mylist; } public void setMylist(ArrayList<Object> list) { mylist = list; } public HashMap<Object, Object> getMymap() { return mymap; } public void setMymap(HashMap<Object, Object> map) { mymap = map; } } }