首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

也路Java循环优化 (转)

2012-12-18 
也说Java循环优化 (转)最近有不少人提出Java循环优化问题,问题分为两类:?1)????for(int i0 i10000 i--

也说Java循环优化 (转)

最近有不少人提出Java循环优化问题,问题分为两类:

?

1

????for(int i=0; i<10000; i--){。。。}

?

?

????for(int i = 100000; i > 0; i--){。。。}

?

这个比较无非是i++和i—的比较。

?

2

for(int i=0; i<1000; i++) {

???????for(int j=0; j<100000; j++) {

???????????。。。

???????}

????}

?

?

for (int i = 0; i < 100000; i++) {

???????for (int j = 0; j < 1000; j++) {

???????????。。。

???????}

????}

?

这个比较主要问题在于循环次数多的放在里面还是外面的问题。

?

我的观点:首先,这种代码上自以为是的优化是没有意义的;其次,拿C语言的思维来考虑这个问题表示Java基本常识都不懂。

分析:

在具体阐明我的观点前有必要做一点Java常识的普及。(注,若没有特别说明,文中sun的指的是被Oracle收购的那个sun,也用来表示Oracle接手的sun公司的一些产品,如sun的jvm,既指Oracle接手sun后的虚拟机,也指未收购时的sun的虚拟机)

1)?????????jvm。

众所周知,这是java虚拟机。但是,很多人,包括初学者甚至一些工作了的人,对jvm的认识仅仅是sun的hotspot虚拟机,就是从sun官网上下载的那个。

而实际上,sun公司制定的是一个规范,即Java虚拟机规范,搜索jvmspec即可得。同时sun也提供了该规范的一个标准实现,就是sun的hotspot虚拟机(N年前的版本就不说了)。但很多人不知道的是,除了sun实现了虚拟机外,还有很多公司也根据自己的需要实现了Java虚拟机,比较常见的有IBM的J9(Websphere中用的),Oracle的JRockit(Weblogic中用的),Apache的Harmony(由于利益等原因,sun和Oracle都没有给它提供兼容性测试),还有openJDK。这些都是比较流行的。诸如此类,还有很多很多。

2)?????????Java指令集

jvm规范中,为Java定义了一套指令集。如iadd,iinc等,指令集用单字节表示,也就是说不超过255个。

关于规范中jvm指令集最需要注意的一点是:指令集指描述了指令该做什么事情,对于如何去做,是留给jvm实现者自己去思考的,所以不同的jvm实现对于同一段代码在效率上可能会有很大的差别。譬如,对于iadd指令,两个int相加,既可以直接交给硬件去做,也可以拐弯抹角的去做,只要最终结果符合jvm规范的描述即可。

3)?????????Java栈

需要知道的是,Java考虑到跨平台的需要,所有指令的操作都不是基于寄存器的,而是内存中的Java栈。在C语言中,有个寄存器用于pc计数器,而在Java中,pc计数器是内存中的一个字。Java栈由栈帧组成,栈帧分为局部变量区,操作数栈和帧数据区。jvm指令的操作数大都源于操作数栈。这与一些语言从寄存器中取操作数是不同的。而局部变量区和操作数栈的大小在编译Java文件时就已经确定了。

?

对于问题一,我们有必要看一下Java中对于i++和i—所使用的指令

public?class Test {

????public?static?void main(String... args) {

???????int i = 0;

???????i++;

???????i--;

????}

}

上面的代码编译后再用javap –c Test查看用到的指令:

Compiled from "Test.java"

public class Test extends java.lang.Object{

public Test();

??Code:

???0:???aload_0

???1:???invokespecial???#1; //Methodjava/lang/Object."<init>":()V

???4:???return

?

public static void main(java.lang.String[]);

??Code:

???0:???iconst_0

???1:???istore_1

???2:??iinc????1, 1

???5:??iinc????1, -1

???8:???return

?

}

从上面我们发现i++和i--其实用的是同一个指令,即iinc,不过操作数不一样罢了;该指令直接修改局部变量区的值,而不需要压栈。至于如何去实现这个指令,不同的人在实现jvm的时候有自己的想法。所以问题一的比较是毫无意义的。你在jvm实现1上运行很快,可能在jvm实现2上面就运行很慢。

?

对于问题二,如上面普及常识所言,不同的jvm可以有不同的实现,不同的优化。与C语言不同之处在于,java的局部变量区在运行一个方法的时候已经分配好了,不需要遇到一个新变量就去分配。另外一点,因为由jvm来执行,这种循环是jvm内部是存在优化余地的,譬如,对于里层的循环变量,在重新下一次循环时就没用了,一些jvm实现就可以重用这个变量。一些JVM可能是纯粹的解释执行字节码,一些JVM可能在启动的时候就把字节码编译成c++本地代码,一些jvm可能用纯硬件芯片来执行指令集,还有一些jvm在运行了一段时间后找出程序热区,仔细优化并将这部分代码编译成c++本地代码来达到最佳效果。所有你能想到的优化都可以在这里做掉。所以不同的jvm实现对于这样的代码效率可能会有很大的差别。

经过本人实测(循环体是数值计算),IBM J9 1.6中两种都很快,Sun hotspot跟J91.6相比不是一个数量级的。但是IBM J9 1.5的实现则相当的慢,跟hotspot比慢的不是一个数量级。有兴趣的可能分别试试openJDK,IBM J9,Jrockit?这些实现的1.5和1.6版本的效率,另外一些jvm还有server和client运行版本的区别,效率也是大不一样的

?

总结,隔了一层虚拟机,什么都有可能!

热点排行