现在的位置: 首页 > 综合 > 正文

java字节码和.NET IL

2013年10月08日 ⁄ 综合 ⁄ 共 1373字 ⁄ 字号 评论关闭
为了方便讨论,以下统将java字节码与.net IL称为“中间指令”;将java.class文件和.net的托管模块或者程序集称作“中间模块”;将java虚拟机和.netCLR统称为“执行者”。

       编译器将源代码编译成中间语言,然后由某一”执行者”将中间语言翻译并执行成某一具体平台下的机器指令。

毫无疑问,在java中这个源代码就是.java文件里的java程序,中间语言就是.class文件里的字节码,而这个执行者就是java虚拟机。

        在.net平台下以C#语言为例,这个源代码就是.cs文件中的c#程序,中间语言就是托管模块中的IL指令,这个执行者就是被称作公共语言运行时的CLR

源代码,中间指令,执行者的关系如下:

 

        这个中间指令到底是什么呢?可以将它理解为一种新的编程语言,他可以完成高级语言所完成的功能。从形式上看,他非常类似于汇编指令。从概念上来讲,他是所有处理器下的汇编指令的超集,他是一个接口。为了方便理解,可以从面向对象的角度来看,如下图所示:

        中间指令(字节码/IL)从概念上讲是一个大的接口,然后所有处理器下的汇编指令都实现了这个接口。因此这个中间指令可以再任何实现了接口的机器上。现在大脑中可以闪现一个词”跨平台”,是的,这样确实为跨平台做了准备。

        由于编译器将源代码编程成了中间指令,而不是具体的某一平台机器指令。所以这个中间模块(.class文件/.net 程序集)可以不用移植到任意的平台上,只要这个平台上有一个相应的虚拟机或者CLR就可以。

       我发现,java的字节码要比.netIL指令多一些。这是因为java字节码可以实现验证功能。举个例子,如果我们在源代码中写了一个加法运算2+3,编译器就会将其编译成iadd 2,3,。但是在.net下,编译器会将其编译成add 2,3.

 

       原因是,java字节码有类型之分,整数加法指令是iadd,长整形加法是ladd指令,浮点数加法是fadd指令…….而在IL中指令是部分类型的,所有加法操作都是add指令。由于java字节码有类型之分,所有可以方便的执行验证功能,一个整形加法不会生成fadd指令。

         但我发现,在java字节码中好像没有溢出检查功能。在.net中,如果我们指定了编译器开关+checked或者在源代码中使用管理checked语句,那么编译生成的是add.ovl指令而不是addadd.ovl会在发生溢出的时候抛出一个overlowException异常。而add指令在溢出时不会抛出任何异常,他会如无其事的继续运行。

         最后一个是关于性能问题,将源代码编程成中间指令,然后在由虚拟机在运行时将中间指令编译成本地指令,这毫无疑问会在运行时造成一定的损失.

性能损失仅发生在第一次方法的调用上,在第一次调用方法时,虚拟机将其编译成本地机器指令,并保存在内存中,以后再调用时,会直接使用这个编译好的指令,而不用在重新编译。

        但是我们知道程序具有局部性原理,在一定的时间内,更倾向于反复调用同一方法,使用同一变量。因此在后续对同一方法的调用中将会获得更好的性能。

同时,虚拟机正变得越来越强大,也许在未来的某一天,他的性能会超过C++

  

抱歉!评论已关闭.