转自:http://hi.baidu.com/algorithms/blog/item/565243d9dbc0fbeb38012f16.html
这篇文章已经挂了很久了,近日进行了修改:
Java语言标准从1996年发布第一版,到2000年发布第二版,再到2004年发布第三版,java语言已经经过了3次大的扩充和改进。功能是越来越多,操作是越来越复杂。显然,性能问题也就越来越突出。本文将力图从java本身分析优化java代码的各种可能。文章的数据未经特别说明,均来自于jdk5.0版本。
1 Java基本数据类型时间分析
因为单独测试一个基本类型的变量很不精确,无论你怎么测,误差都很大。所以,我们只能大致的给出速度上的差别。
变量的访问速度和访问的类型是有很大关系的,一般我们直接使用2个变量的操作时间来衡量变量的访问速度。显然,byte + byte的速度和int + int的速度肯定是不同的。我们对以下几类基本操作进行了速度测试:加减(+,-)、乘(*)、除(/)、移位(>>,<<,>>>,<<<)和布尔运算(|,&,^)。为了保证数据的有效性,测试得到了3份结果,取平均值,得到下面的各个基本数据类型的大致时间花销比例如下表(以下均以此作为参考对象,一个时间单位在我的机器上大约是600ps,即0.6ns,也就是6e-10秒):
|
加减
|
乘
|
除
|
移位
|
布尔运算
|
byte
|
1.5
|
6
|
50
|
1.5
|
1
|
short
|
1.2
|
5.5
|
50
|
1.2
|
1
|
int
|
1
|
5
|
48
|
1
|
1
|
long
|
5
|
10
|
140
|
8.5
|
2
|
float
|
15
|
600
|
350
|
-
|
-
|
double
|
15
|
600
|
350
|
-
|
-
|
从表中我们可以看出:
1. int的运算速度最快,short次之,byte再次之,long再次之。float和double运算速度最慢。
2. 除法比乘法慢的太多,基本上除法是乘法的9倍时间。当然,除了浮点型外。根据intel cpu的参考数据,乘法计算时间是移位运算的4-5倍是比较正常的。
3. long类型的计算很慢,建议一般少使用它。
4. double运算速度和float相当;
5. 浮点的乘法比除法要慢。但是,这个结果并不能真正说明问题。这个结果只是一个一般性的,在特殊情况下,乘法还是比除法快,比如:floatA * floatB 仍然是比floatA / (1/floatB)快。从实际的数据结果来讲,乘法的时候,乘数越小速度越快,特别是在乘数比3小的时候,乘法时耗接近20,大于4的时候,几乎都是600的时耗。除法恰好相反,除数大于1的时候,时耗一般都是350,可是,当除数小于1的时候,时耗就变成了700了。
对于大家关心的移位和乘除2的问题,jdk5.0已经做了部分处理。即“var *=2”和“var <<=1”耗费一样。但是,除法并没有进行这类处理,即“var /= 2”耗费和基本的除法一样。
2 Java类和接口调用时间分析
2.1 类的创建
虽然面向对象思想已经深入人心,但他在带来快捷方面的编程风格的时候,也带来了低下的效率。在Java中,反应最快的是Object类(这也是显然的),建立一个新的Object类时耗仅仅为20单位。而一个空类(即没有声明任何Methods和Fields)的建立时间则增加到了惊人的400单位。如果再给类增加一些字段的话,时间耗费并没有特别大的增加,每增加一个int类型字段大概增加30个单位。
仅仅就创建时间来说,内嵌的类型都有不错的表现。比如,创建一个int数组(仅仅包含一个元素)的时间只比创建一个Object对象的时间多一倍。当然,如果你创建的数组对象包含1000个元素的话,其创建时间显然还会加上内存管理的时间了,它的时间大概是1万个时间单位。请注意,我们这里讨论的时间单位其实十分小,1万个时间单位也仅仅只是有0.006毫秒(0.000006秒)。创建一个byte、short、int、long、float和double数组对象的时间消耗几乎是一样的。
2.2 方法的调用
Java在这个方面有一点做得很好,就是调用一个只有很少量代码的方法的时耗和直接把这段代码写到本地的时耗相差很小。当然不包括需要分配很多本地变量的情况。
调用本类(this指针)的方法是最快的,时间在1-2个单位。调用其它类的静态方法也很快,速度和调用本来方法差不多。调用其它类的非静态方法速度就慢一些,在1.5-2.5个时间单位之间。
调用继承接口的方法是十分缓慢的,是调用普通方法的3倍。但是,如果在实现接口的时候加上final关键字的话,调用这个方法的时耗就和普通方法差不多了。
最慢的是已经同步化了的方法。即加上了synchronized关键字的方法。调用它的时耗比普通方法高出了近20倍。如果不是万不得已,不要把synchronized加到方法上面,实在不行的话,你可以把它加到代码块上去,这种加法比直接加到方法上面快一点。
注意,因为方法大部分时候都是完成很多事情的,所以,十分注意调用方法的开销是没有必要的,因为这个时间和方法执行需要的时间比较起来只是毛毛雨。
3 Java基本操作时间耗费
3.1 基本语句
for循环一次的时间耗费在5个单位左右,本地int变量赋值一次的时间耗费在1-2个单位。下表列出了各种操作的时间耗费:
操作
|
时间耗费
|
int var = var
|
1.5
|
int array[0] = array[0]
|
4
|
for
|
6
|
throw --- catch
|
5000
|
3.2 Cast的时间耗费
下表是各种类型之间转化的时间耗费:
转化形式
|
时耗
|
SubClass = (SubClass) SuperClass
|
4
|
Interface = (Interface) Class
|
4
|
int à byte, intà char, intà short, intà long
|
1
|
intàfloat, intàdouble
|
3
|
int? long
|
10-15
|
int? float, int? double
|
15-20
|
long? float, long? double
|
30-40
|
4 基本优化策略
基本优化策略的天字第一条就是:不要优化!优化代码会使得代码难以理解,代码之间的逻辑结构会变得十分混乱。所以,优化大师们的建议就是:不到万不得已,千万不要优化你的代码。可惜的是,在搜索引擎方面,处处都是效率的考虑。
基本的优化策略有以下几条:
1. 选定优化目标。优化不是对所有代码进行优化,这是因为优化代码的代价很高。优化只需要针对少部分代码进行。在这里,90/10或者80/20规则发挥着重要作用。找到代码中最影响速度的地方,然后把块骨头啃下来!
2. 操作符简约。换一个操作符代替原有操作符。这里说的最主要例子就是:用“>>=n”替换“/= 2^n”和“<<=n”替换“*=2^n”。Java用不着第2种替换。
3. 共同表达是提取。提取2个表达式中相同的部分,避免同一个式子重复计算。比如:
double x = d * a*b;
double y = e * a*b;
就可以化为:
c = a*b;
x = d*c;
y = e*c;
4. 代码移动。把那些在运算中不改变值的变量放到前面先计算好。比如:
for(int i=0;i<x.length;i++)
{
x[i] *= Math.PI * Math.cos(y);
}
就可以修改为:
double d = Math.PI * Math.cos(y);
for(int i=0;i<x.length;i++)
{
x[i] *= d;
}
5. 分解循环。循环可以简化代码,同时,他们也增加了额外的循环开销。可以通过减少循环次数或者取消循环来获得更好的性能。比如:
for(int i=0;i<1000000;i++)
{
x[i] = i;
}
就能够变成:
for(int i=0;i<1000000;i+=2)
{
x[i] = i;
x[i+1] = i+1;
}
6. 循环的替换。一般认为把“for(i=0;i<n;i++)”替换成“for(i=n;--i>=0;)”会有更好的效果。不过,我们的测试结果显示,在JDK5.0的环境下面,这种方式几乎没有任何速度提升。
7. 取消for判断。把“for(i=0;i<n;i++)”转化为“for(i=0;;i++)”,如果里面的代码能够在i>=n的时候出错的话,这段循环就能够自己结束(通过Exception)。可是,测试的结果说明,只有在n特别大的时候,比如1000万,这种方式才能提高速度。其依据是:exception特别耗时。
分享到:
相关推荐
具体包括:性能优化策略、程序编写及硬件服务器的基础知识、Java API优化建议、算法类程序的优化建议、并行计算优化建议、Java程序性能监控及检测、JVM原理知识、其他相关优化知识等。 通读《大话Java性能优化》后...
- 了解下我们为什么要学习JVM优化 - 掌握jvm的运行参数以及参数的设置 - 掌握jvm的内存模型(堆内存) - 掌握jamp命令的使用以及通过MAT工具进行分析 - 掌握定位分析内存溢出...- 看懂Java底层字节码 - 编码的优化建议
具体包括:性能优化策略、程序编写及硬件服务器的基础知识、Java API优化建议、算法类程序的优化建议、并行计算优化建议、Java程序性能监控及检测、JVM原理知识、其他相关优化知识等。 通读《大话Java性能优化》后,...
主要介绍了Java 并发编程学习笔记之Synchronized底层优化的相关资料,主要包含了重量级锁,轻量级锁,偏向锁和其他优化等方面,有需要的小伙伴可以参考下
java虚拟机分析与优化PPT(演讲:李镭) 李镭——现任IBM中国有限公司软件部WebSphere高级工程师。 2002年加入IBM公司软件部,至今一直从事中间件产品家族的售前和售后工作。为IBM的重要合作伙伴提供软件的技术支持和...
J2ME优化压缩PNG文件 4个目标文件 内容索引:JAVA源码,综合应用,J2me游戏,PNG,图形处理 这是个J2ME控制台程序,它能剔除PNG文件中的非关键数据段,减少文件大小从而达到压缩图片的目的。而图片的质量并不会受到损失...
主要介绍了Java synchronize底层实现原理及优化,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
│ Java面试题67:数据库优化之数据库表设计遵循范式.mp4 │ Java面试题68:选择合适的数据库引擎.mp4 │ Java面试题69:选择合适的索引.mp4 │ Java面试题70:使用索引的一些技巧.mp4 │ Java面试题71:数据库优化...
主要是Java后端的,16K左右的,涉及SE、WEB、三大框架SSM、springboot、MQ、数据库、springcloud、JVM、Redis、多线程、hashmap的底层、面试技巧等 SSM涉及浅层的底层,如IOC、AOP,专为没看过源码的人应付面试准备...
J2ME优化压缩PNG文件 4个目标文件 内容索引:JAVA源码,综合应用,J2me游戏,PNG,图形处理 这是个J2ME控制台程序,它能剔除PNG文件中的非关键数据段,减少文件大小从而达到压缩图片的目的。而图片的质量并不会受到损失...
J2ME优化压缩PNG文件 4个目标文件 内容索引:JAVA源码,综合应用,J2me游戏,PNG,图形处理 这是个J2ME控制台程序,它能剔除PNG文件中的非关键数据段,减少文件大小从而达到压缩图片的目的。而图片的质量并不会受到损失...
不同的平台,内存模型是不一样的,但是jvm的内存模型规范是统一的。...JVM定义了自己的内存模型,屏蔽了底层平台内存管理细节,对于java开发人员,要清楚在jvm模型的基础上,如果解决多线程的可见性和有序性。
J2ME优化压缩PNG文件 4个目标文件 内容索引:JAVA源码,综合应用,J2me游戏,PNG,图形处理 这是个J2ME控制台程序,它能剔除PNG文件中的非关键数据段,减少文件大小从而达到压缩图片的目的。而图片的质量并不会受到...
J2ME优化压缩PNG文件 4个目标文件 内容索引:JAVA源码,综合应用,J2me游戏,PNG,图形处理 这是个J2ME控制台程序,它能剔除PNG文件中的非关键数据段,减少文件大小从而达到压缩图片的目的。而图片的质量并不会受到...
深入浅出快速掌握企业级Mysql底层原理与优化技巧
J2ME优化压缩PNG文件 4个目标文件 内容索引:JAVA源码,综合应用,J2me游戏,PNG,图形处理 这是个J2ME控制台程序,它能剔除PNG文件中的非关键数据段,减少文件大小从而达到压缩图片的目的。而图片的质量并不会受到...
理解了Java虚拟机,深入细致的了解了Java技术底层,才能使自己的程序发挥Java技术的优势。 本书详细解释了JVM的体系结构,包括Java栈、堆、方法区和执行引擎,还深入讨论了各种技术实现,比如解释,即时编译以及...
第二章 Java并发机制的底层实现原理 volatile的两条实现原则: 1. Lock前缀指令会引起处理器缓存回写到内存 2. 一个处理器的缓存回写到内存会导致其他处理器的缓存无效。 volatile的使用优化:共享变量会被...
J2ME优化压缩PNG文件 4个目标文件 内容索引:JAVA源码,综合应用,J2me游戏,PNG,图形处理 这是个J2ME控制台程序,它能剔除PNG文件中的非关键数据段,减少文件大小从而达到压缩图片的目的。而图片的质量并不会受到损失...
Java集合:List底层实现、Map底层实现等;Java并发编程:ThreadLocal、Java内存模型、锁、并发工具类、线程池等;JVM(Java虚拟机):Java内存管理详解、垃圾回收机制、垃圾回收器等;MySQL:基础知识、存储引擎、...