- 浏览: 124348 次
- 性别:
- 来自: 上海
文章分类
最新评论
源地址:http://blog.csdn.net/maritimesun/article/details/8065143
自从第一个Java版本开始,很多开发人员一直都在尝试让Java获得最少和C/C++一样的表现。JVM提供商尽他们最大的努力去实现一些新的JIT算法,但是还是有很多需要做的,特别是在我们使用Java的方法上。
例如,在对象<->文件序列化上就差距很大--尤其在读写内存对象上。我将就这个主题做一些解释和分享。
所有的测试都是在下面这个对象上执行的:
1 |
public class TestObject implements Serializable { |
2 |
3 |
private long longVariable; |
4 |
private long [] longArray; |
5 |
private String stringObject; |
6 |
private String secondStringObject; //just for testing nulls |
7 |
8 |
/* getters and setters */ |
9 |
} |
为了简单起见,我将只贴出写入方法(尽管读取类似),完整的源码在GitHub上可以找到(http://github.com/jkubrynski/serialization-tests)
最标准的java序列化(我们都是从这里学起的)是这样的:
01 |
public void testWriteBuffered(TestObject test, String fileName) throws IOException { |
02 |
ObjectOutputStream objectOutputStream = null ; |
03 |
try { |
04 |
FileOutputStream fos = new FileOutputStream(fileName); |
05 |
BufferedOutputStream bos = new BufferedOutputStream(fos); |
06 |
objectOutputStream = new ObjectOutputStream(bos); |
07 |
objectOutputStream.writeObject(test); |
08 |
} finally { |
09 |
if (objectOutputStream != null ) { |
10 |
objectOutputStream.close(); |
11 |
} |
12 |
} |
13 |
} |
提升标准序列化速度的最简单方法时使用RandomAccessFile对象:
01 |
public void testWriteBuffered(TestObject test, String fileName) throws IOException { |
02 |
ObjectOutputStream objectOutputStream = null ; |
03 |
try { |
04 |
RandomAccessFile raf = new RandomAccessFile(fileName, "rw" ); |
05 |
FileOutputStream fos = new FileOutputStream(raf.getFD()); |
06 |
objectOutputStream = new ObjectOutputStream(fos); |
07 |
objectOutputStream.writeObject(test); |
08 |
} finally { |
09 |
if (objectOutputStream != null ) { |
10 |
objectOutputStream.close(); |
11 |
} |
12 |
} |
更高深点的技术是使用Kryo框架,新旧版本的差距是很大的,我做过测试。因为性能比较上并没有体现出特别引人注意的差异,所以我将使用2.x版本,因为它对用户更友好而且更快些。
01 |
private static Kryo kryo = new Kryo(); // version 2.x |
02 |
03 |
public void testWriteBuffered(TestObject test, String fileName) throws IOException { |
04 |
Output output = null ; |
05 |
try { |
06 |
RandomAccessFile raf = new RandomAccessFile(fileName, "rw" ); |
07 |
output = new Output( new FileOutputStream(raf.getFD()), MAX_BUFFER_SIZE); |
08 |
kryo.writeObject(output, test); |
09 |
} finally { |
10 |
if (output != null ) { |
11 |
output.close(); |
12 |
} |
13 |
} |
14 |
} |
最后一个方案是在Martin Thompson的文章中提到的(Native C/C++ Like Performance For Java Object Serialisation),介绍了怎样在Java中像C++那样和内存打交道。
01 |
public void testWriteBuffered(TestObject test, String fileName) throws IOException { |
02 |
RandomAccessFile raf = null ; |
03 |
try { |
04 |
MemoryBuffer memoryBuffer = new MemoryBuffer(MAX_BUFFER_SIZE); |
05 |
raf = new RandomAccessFile(fileName, "rw" ); |
06 |
test.write(memoryBuffer); |
07 |
raf.write(memoryBuffer.getBuffer()); |
08 |
} catch (IOException e) { |
09 |
if (raf != null ) { |
10 |
raf.close(); |
11 |
} |
12 |
} |
13 |
} |
TestObject写入方法如下:
01 |
public void write(MemoryBuffer unsafeBuffer) { |
02 |
unsafeBuffer.putLong(longVariable); |
03 |
unsafeBuffer.putLongArray(longArray); |
04 |
// we support nulls |
05 |
boolean objectExists = stringObject != null ; |
06 |
unsafeBuffer.putBoolean(objectExists); |
07 |
if (objectExists) { |
08 |
unsafeBuffer.putCharArray(stringObject.toCharArray()); |
09 |
} |
10 |
objectExists = secondStringObject != null ; |
11 |
unsafeBuffer.putBoolean(objectExists); |
12 |
if (objectExists) { |
13 |
unsafeBuffer.putCharArray(secondStringObject.toCharArray()); |
14 |
} |
15 |
} |
直接内存缓冲区类(已简化了的,仅仅为了展示这个思想)
01 |
public class MemoryBuffer { |
02 |
// getting Unsafe by reflection |
03 |
public static final Unsafe unsafe = UnsafeUtil.getUnsafe(); |
04 |
05 |
private final byte [] buffer; |
06 |
07 |
private static final long byteArrayOffset = unsafe.arrayBaseOffset( byte []. class ); |
08 |
private static final long longArrayOffset = unsafe.arrayBaseOffset( long []. class ); |
09 |
/* other offsets */ |
10 |
11 |
private static final int SIZE_OF_LONG = 8; |
12 |
/* other sizes */ |
13 |
14 |
private long pos = 0; |
15 |
16 |
public MemoryBuffer(int bufferSize) { |
17 |
this.buffer = new byte[bufferSize]; |
18 |
} |
19 |
20 |
public final byte[] getBuffer() { |
21 |
return buffer; |
22 |
} |
23 |
24 |
public final void putLong(long value) { |
25 |
unsafe.putLong(buffer, byteArrayOffset + pos, value); |
26 |
pos += SIZE_OF_LONG; |
27 |
} |
28 |
29 |
public final long getLong() { |
30 |
long result = unsafe.getLong(buffer, byteArrayOffset + pos); |
31 |
pos += SIZE_OF_LONG; |
32 |
return result; |
33 |
} |
34 |
35 |
public final void putLongArray(final long[] values) { |
36 |
putInt(values.length); |
37 |
long bytesToCopy = values.length << 3; |
38 |
unsafe.copyMemory(values, longArrayOffset, buffer, byteArrayOffset + pos, bytesToCopy); |
39 |
pos += bytesToCopy; |
40 |
} |
41 |
42 |
43 |
public final long[] getLongArray() { |
44 |
int arraySize = getInt(); |
45 |
long[] values = new long[arraySize]; |
46 |
long bytesToCopy = values.length << 3; |
47 |
unsafe.copyMemory(buffer, byteArrayOffset + pos, values, longArrayOffset, bytesToCopy); |
48 |
pos += bytesToCopy; |
49 |
return values; |
50 |
} |
51 |
52 |
/* other methods */ |
53 |
} |
几个小时的Caliper测试结果如下:
Full trip [ns] | Standard deviation [ns] | |
Standard | 207307 | 2362 |
Standard on RAF | 42661 | 733 |
KRYO 1.x | 12027 | 112 |
KRYO 2.x | 11479 | 259 |
Unsafe | 8554 | 91 |
在最后我们可以得出一些结论:
- Unsafe序列化比标准的java.io.Serizlizable快了23倍
- 使用RandomAccessFile可以使标准的有缓冲序列化加速将近4倍
- Kryo-dynamic序列化大约比手写实现的直接缓冲满了35%
最后,就像我们看到的那样,还是没有绝对的答案。对于我们中的大多数人来说,获得3000ns(0.003ms)的速度提升是不值得为每个需要序列化的对象来写单独实现的。在标准的方案中,我们大多数选择Kryo 。然而,在惜时如金的低延时系统中,这个选择将会是完全不同的。
发表评论
-
(转)JDK工具(查看JVM参数、内存使用情况及分析等)
2018-12-25 15:50 345https://www.cnblogs.com/z ... -
[转]jstat查看jvm的GC情况
2018-12-25 15:38 553jstat 1. jstat -gc pid ... -
转一个 jmap 的基本使用方法
2017-04-05 11:52 535原文:http://hbluojiahui.bl ... -
(转)JVM内存堆布局图解分析
2017-04-05 11:56 403转载原文出处:http://www.codeceo.com/ ... -
(转)系统吞吐量(TPS)、用户并发量、性能测试概念和公式
2017-03-27 11:19 452PS:下面是性能测试的主要概念和计算公式,记录下: 一.系 ... -
(转)深入理解Major GC, Full GC, CMS
2016-11-02 11:27 499原文:http://blog.csdn.net/iter_ ... -
(转)OpenSSL 1.0.0生成p12、jks、crt等格式证书的命令个过程
2016-07-26 18:51 664OpenSSL 1.0.0生成p12、jks、crt等格式 ... -
(转)Java 内存区域和GC机制
2016-07-26 14:09 368录 Java垃圾回收概况 Java内存区域 Java ... -
Understanding CMS GC Logs
2016-07-26 11:06 532Understanding CMS GC Logs By ... -
(转)Java动态代理机制详解(JDK 和CGLIB,Javassist,ASM)
2016-07-08 17:56 600源地址:http://blog.csdn.net/lu ... -
linux下查看最占性能的JAVA进程
2016-03-08 11:58 634记录一下自己常用的linux系统命令,方便以后查阅,发觉记忆 ... -
(转,精)Java 多线程 并发编程
2015-10-10 19:50 800源地址:http://blog.csdn.n ... -
java虚拟机内存监控工具jps,jinfo,Jstack,jstat,jmap,jhat使用
2015-09-21 13:14 1202源地址:http://my.oschina. ... -
(转)JMM模型
2014-11-11 16:53 488源地址:http://blog.csdn.net/gt ... -
(转)《深入浅出 Java Concurrency》目录
2014-11-10 15:55 402原文地址:http://www.blogjava.net/x ... -
(转)TCP/IP、Http、Socket的区别
2014-08-21 10:32 813源地址: http://jingyan.baidu.com/ ... -
(转)Swift里的CAP理论和NWR策略应用
2014-08-12 17:25 612源地址:http://blog.sina.com.cn/s/ ... -
(转)Java多线程编程的常见陷阱
2014-06-25 13:14 498源地址:http://developer.51cto.com ... -
(转)Java 正确的做字符串编码转换
2014-03-11 21:52 657原文:http://hi.baidu.com/sodarf ... -
深入理解java内存模型系列文章
2013-12-30 10:57 438深入理解java内存模型系列文章 源地址: htt ...
相关推荐
以下是一些加快Java文件序列化速度的方法: 1. **优化对象结构**: - **减少嵌套深度**:如果对象层次太深,序列化和反序列化时会增加额外的时间开销。尽量简化对象结构,避免过多的嵌套。 - **精简对象属性**:...
它们允许序列化和反序列化Java对象,使得对象能在网络间传输。 5. **NIO(New Input/Output)**: Java NIO(非阻塞I/O)提供了一种新的方式来处理I/O操作,尤其是对于高并发的网络应用。它使用Channel和Selector...
MessagePack就是一种高效、跨语言的数据序列化库,它专为速度和效率而设计,特别适合处理大数据量的场景。 **MessagePack简介** MessagePack是一种轻量级的二进制序列化格式,它的目标是比JSON更快、更小。在保持...
本章将讨论如何实现JavaBeans的序列化和反序列化。 #### 8. 定制:为应用程序构建者提供Bean支持 为了让Bean更加灵活和易于使用,开发人员可能会添加额外的支持,如图形界面或配置选项。这部分内容将展示如何为...
4. **SaveLoadManager**:保存和加载游戏进度的功能类,可能实现了序列化技术,将游戏状态转化为文件,以便用户可以随时继续游戏。 5. **Solver**:如果游戏包含自动解决功能,这个类将包含高级算法,如回溯法或...
分布式计算是现代信息技术中的一个重要研究领域,它涉及将计算任务拆分成多个子任务,并在不同计算机上进行并行处理以加快整体计算速度。由于单台计算机的计算能力有限,分布式计算模型在处理大型复杂问题时表现出其...
protoc jar文件用于编译.proto文件,将定义的协议消息类型转换为Java类,而Java运行时库则是在应用程序中处理序列化和反序列化的必要依赖。 在Android开发中,protobuf被广泛应用于服务器与客户端之间的数据交换,...
### Java报表JFreeChart开发知识点总结 #### 1. 简介 ##### 1.1 什么是JFreeChart JFreeChart是一款免费且开源的Java图表库,它提供了多种类型的图表绘制功能,如饼图、条形图、折线图等。JFreeChart适用于各种Java...
开发者可以使用protobuf编译器将.proto文件转换为目标语言(如C++、Java、Python等)的源代码,生成的类库提供了序列化和反序列化的API,使得数据可以在不同系统之间进行高效通信。 在“protobuf-all-3.6.1.zip”这...
要将leveldb移植到Java平台,通常需要实现一个Java版的leveldb接口,这包括数据序列化、存储管理和读写操作等功能。移植过程主要包括以下步骤: 1. 编译JNI库:首先,需要编译出适用于Java的leveldb JNI库,这涉及到...
3. **FastJson**:FastJson是阿里巴巴开源的一款高性能的JSON库,用于JSON的序列化和反序列化。在爬虫项目中,FastJson可以帮助将抓取到的JSON格式数据快速转换为Java对象,便于存储和后续处理。同时,它也能将Java...
2. **编译器**:`protoc`是Protocol Buffer提供的编译器,它可以将.proto文件编译成不同编程语言(如C++、Java、Python等)的源代码,生成的类库提供了序列化和反序列化的接口。 3. **序列化与反序列化**:Protocol...
从LCD到RDF 将ILCD XML序列化中的LCA数据转换为(大致等效)RDF / XML序列化ILCD模式非常大,此代码仅转换很小的子集,足以表示进程及其输入和输出流。 这样做的主要动机是探索关联数据和LCA的机会和问题。依存关系...
- 使用Java的`ObjectOutputStream`和`ObjectInputStream`类可以序列化和反序列化对象,将棋盘状态保存到文件中,然后在需要时读取。保存时,将棋盘、棋子、玩家等核心对象写入文件;加载时,从文件读取这些信息恢复...
5. **索引优化**:为了加快查询速度,数据库可能会创建索引,设计者需要考虑如何有效地利用索引来提升系统的性能。 **毕业设计相关** 作为毕业设计,这个项目可能包含以下环节: 1. **需求分析**:对办公自动化...
Ehcache是一个高性能、轻量级的Java分布式缓存库,它被广泛应用于提升应用程序的性能,通过存储经常访问的数据来减少对数据库的依赖,从而加快系统的响应速度。本入门案例将带你了解如何使用Ehcache实现分布式缓存,...
- 序列化:默认情况下,spymemcached使用Java序列化。但你可以自定义序列化策略,比如使用Gson或Jackson库进行JSON序列化,以提高性能和可读性。 - 批量操作:支持批量设置、获取和删除键值对,减少网络往返次数,...
- **存储优化**:在数据库或文件系统中,protobuf序列化的数据可以减少存储空间,加快读写速度。 5. **优势与局限**: - **优点**:效率高,占用空间小,支持多种语言,易于扩展和维护。 - **局限**:学习曲线较...
7. **互联网传输**:ZIP文件常用于互联网上传输,因为它们可以减小文件大小,加快下载速度。 8. **归档用途**:ZIP文件也常用于备份和归档,将大量文件整合在一起,方便存储和恢复。 9. **开发工具集成**:许多...