Java 自动装箱性能
2016-06-19 23:27
393 查看
Java 的基本数据类型(int、double、 char)都不是对象。但由于很多Java代码需要处理的是对象(Object),Java给所有基本类型提供了包装类(Integer、Double、Character)。有了自动装箱,你可以写如下的代码
编译器自动将它转换为
然而,Java虚拟机不是每次都能理解这类过程,因此要想得到好的系统性能,避免不必要的装箱很关键。这也是 OptionalInt 和 IntStream 等特殊类型存在的原因。在这篇文章中,我将概述JVM很难消除自动装箱的一个原因。
实例
例如,我们想要计算任意一类数据的编辑距离(Levenshtein距离),只要这些数据可以被看作一个序列:
只要两个对象可以被看作List,这个类就可以计算它们的编辑距离。如果想计算String类型的距离,那么就需要把String转变为List类型:
由于Java泛型的实现方式,不能有List类型,所以要提供List和装箱操作。(注:Java10中,这个限制也许会被取消。)
基准测试
为了测试 distance() 方法的性能,需要做基准测试。Java中微基准测试很难保证准确,但幸好OpenJDK提供了JMH(Java Microbenchmark Harness),它可以帮我们解决大部分难题。如果感兴趣的话,推荐大家阅读文档和实例;它会很吸引你。以下是基准测试:
(返回方法的结果,这样JMH就可以做一些操作让系统认为返回值会被使用到,防止冗余代码消除影响了结果。)
以下是结果:
分析
为了查看代码热路径(hot path)上的结果,JMH集成了Linux工具perf,可以查看最热代码块的JIT编译结果。(要想查看汇编代码,需要安装hsdis插件。我在AUR上提供了下载,Arch用户可以直接获取。)在JMH命令行添加 -prof perfasm 命令,就可以看到结果:
输出内容很多,但上面的一点内容就说明装箱没有被优化。为什么要和0x7f/0×80的内容做比较呢?原因在于Character.valueOf()的取值来源:
可以看出,Java语法标准规定前127个char的Character对象放在缓冲池中,Character.valueOf()的结果在其中时,直接返回缓冲池的对象。这样做的目的是减少内存分配和垃圾回收,但在我看来这是过早的优化。而且它妨碍了其他优化。JVM无法确定 Character.valueOf(c).charValue() == c,因为它不知道缓冲池的内容。所以JVM从缓冲池中取了一个Character对象并读取它的值,结果得到的就是和 c 一样的内容。
解决方法
解决方法很简单:
用显式的装箱代替自动装箱,就避免了调用Character.valueOf(),这样JVM就很容易理解代码:
虽然代码中加了一个内存分配,但JVM能理解代码的意义,会直接从String中获取char字符。性能提升很明显:
速度提升了14%。用 -prof perfasm 命令可以显示,改进以后是直接从String中拿到char值并在寄存器中比较的:
总结
装箱是HotSpot的一个弱项,希望它能做到越来越好。它应该多利用装箱类型的语义,消除装箱操作,这样以上的解决办法就没有必要了。
以上的基准测试代码都可以在GitHub上访问。
原文链接: tavianator 翻译: ImportNew.com - rainsbaby
译文链接: http://www.importnew.com/16737.html
[ 转载请保留原文出处、译者和译文链接。]
实例
例如,我们想要计算任意一类数据的编辑距离(Levenshtein距离),只要这些数据可以被看作一个序列:
基准测试
为了测试 distance() 方法的性能,需要做基准测试。Java中微基准测试很难保证准确,但幸好OpenJDK提供了JMH(Java Microbenchmark Harness),它可以帮我们解决大部分难题。如果感兴趣的话,推荐大家阅读文档和实例;它会很吸引你。以下是基准测试:
以下是结果:
为了查看代码热路径(hot path)上的结果,JMH集成了Linux工具perf,可以查看最热代码块的JIT编译结果。(要想查看汇编代码,需要安装hsdis插件。我在AUR上提供了下载,Arch用户可以直接获取。)在JMH命令行添加 -prof perfasm 命令,就可以看到结果:
解决方法
解决方法很简单:
装箱是HotSpot的一个弱项,希望它能做到越来越好。它应该多利用装箱类型的语义,消除装箱操作,这样以上的解决办法就没有必要了。
以上的基准测试代码都可以在GitHub上访问。
原文链接: tavianator 翻译: ImportNew.com - rainsbaby
译文链接: http://www.importnew.com/16737.html
[ 转载请保留原文出处、译者和译文链接。]
相关文章推荐
- Java基础知识
- java基础(一)
- 怎样学习java,漫谈java学习之路
- 设置jdk环境变量时lib中的rt.jar ,dt.jar ,tool.jar是什么,作用是什么
- Java 集合系列11之 Hashtable详细介绍(源码解析)和使用示例
- 学习日志---treemap
- java基础知识笔记
- java中web应用中重定向与转发的区别
- java基础篇---枚举详解
- java基础第七天
- java基础第十天
- java基础第十二天
- java基础第十三天
- java基础第十四天
- java基础第十六天
- java基础第十七天
- java基础数据类型包装类
- equals与null
- java基础第三天_数组
- java基础第五天_静态代码块、类的继承和接口