随着DEC(Digital Equipment Corp)公司Alpha处理器在1992年末的发布,就意味着这个世界开始进入64位计算的时代,紧接着,全球几大主要计算机公司,如IBM、Hewlett-Packard(惠普)、Fujitsu(富士通)、Sun Microsystems,也发布了各自相应的产品进入到 "64位"这个市场。在1995年,Fujitsu旗下的HAL Computer发布了业界第一台基于64位SPARC CPU的工作站--"SPARC64";此后不久,Sun发布了大众期盼已久的Ultra 1、Ultra 2工作站,其内置了Sun的64位UltraSPARC处理器;时间转换到1997年,IBM发布了其第一个64位PowerPC RISC芯片--"RS64";在1998年,IBM对RS64进行改良,使其支持SMP,这就是Power 3。如今看起来,对64位计算来说,其整整花了五年的时间,才在2003年开始大量进入市场。
在本文中,将主要涉及两个现在广泛应用的64位平台--AMD64与PowerPC64,并分别使用IBM与Sun Microsystems这两个Java语言巨头提供的Java虚拟机(JVM),通过SPECjvm98与SPECjbb2000的测试,来评价32位与64位中JVM的性能。(注:SPECjvm98与SPECjbb2000来自Standard Performance Evaluation Corp http://www.spec.org/)
AMD64是Advanced Micro Devices(AMD)公司的64位平台,其扩展了工业标准的x86指令集架构,并设计在不降低任何性能的前提下,于32位模式中完全兼容现有的x86应用程序与操作系统。在2003年4月,AMD发布了Opteron,遵循AMD64架构的第一款处理器。
与其同时,2003年,IBM发布了PowerPC 970,其是源自IBM Power 4双核CPU的单核处理器,从此,IBM把64位PowerPC架构带到了桌面系统与低端服务器领域。另外要说明一点,PowerPC 970也像Power 4一样,可在不降低性能的前提下,本地执行32位指令。不久之后,在2003年8月,由Apple Computer公司设计、基于PowerPC 970 CPU的Power Mac G5电脑上市。
Java背景介绍
在第一款64位处理器诞生不久,Java技术也出世了,并由此改写历史。Java是一种健壮的、通用的、面向对象的、构架中立的、可移植的、安全的、多线程的编程语言,并带有隐式内存管理功能。Java面向对象的特性在很大程度上与C++相似,但加入了更多的接口与扩展以创建更具灵活性的解决方案。与C++不同的是,Java不支持操作符重载、多重继承和自动类型强制。Java通过广泛的运行时检查和内置的例外处理机制,达到健壮性的目的;编译器所生成的只是字节码指令,其是独立于任何特定平台的,这样就保证了架构中立性;可移植性是通过指定基本数据类型大小和其算术操作符的行为来达到的,例如,int总表示一个有符号的32位整数,而float总表示一个32位的IEEE 754浮点数。Java同时也有一系列的同步原语,其基于广泛使用的条件变量范式;自动内存垃圾回收(GC)简化了Java编程的难度,并极大地降低了bug的数目,但也使运行机制稍微复杂了点。
在1991年,也就是DEC公司发布第一款64位处理器的前一年,Sun Microsystems开始了一个名为"the Green Project"的计划,目的是要抢占"下一波计算"的先机,并为此提前做好准备;计划得出的最初结论是,移动数字设备与计算机的融合将会很快出现。在1992年的夏天,计划小组演示了*7(星7),一个通过动画式触摸屏控制的交互性手持娱乐设备;通过使用Oak--一种全新的编程语言,这个设备可控制很多不同的平台。而由James Gosling开发的Oak,其最主要的特点在于它是一个彻底独立于处理器的语言。在往后的几年中,这种语言被用于Internet,之后成为大众所知的Java,而"Oak"这个名字则因为版权问题从此消失了。
在1995年5月,Sun正式宣布Java的诞生,这是一种程序员只需编写一次,但却可在多种操作系统及多种硬件平台上运行的语言--"编写一次,随处运行";在1996年,Sun发布了Java开发工具包(JDK 1.0),其后不久,10个主要的操作系统开发商宣布支持Java技术,当中也包括Microsoft,其以每年大约375万美元取得五年时间的Java许可协议;在1996年10月,Sun发布了Java平台的第一个即时(JIT)编译器;在1997年2月,JDK 1.1面世,在随后的三周时间里,达到了22万次的下载量,到了1998年初,这个数字达到两百万。
在1998年末,Java 2平台发布了;大概半年后,也就是1999年年中,Sun发布了三个版本的Java平台:J2ME(Java 2 Micro Edition),应用于移动、无线及有限资源的环境;J2SE(Java 2 Standard Edition),应用于桌面环境;J2EE(Java 2 Enterprise Edition),应用于基于Java的应用服务器。此后,广泛应用的Java技术出现了一些framework,如Enterprise JavaBeans (EJB)和JavaServer Pages (JSP)。Java技术的随后一次升级,是出现在2000年5月的J2SE 1.3,几周后,其获得了Apple公司Mac OS X的工业标准的支持。
J2SE 1.4发布于2002年2月份,对Java平台来说,这是一个几乎全新的产品,与J2SE 1.3相比,其多了近62%的类和接口。在这些新特性当中,还提供了广泛的XML支持、安全套接字支持(通过SSL与TLS协议)、全新的I/O API、正则表达式,日志与断言。
在2004年9月,是Java最近的一次发布--J2SE 5.0(内部版本号1.5.0),代号"Tiger",现已提供公开下载。Tiger包含了从1996年发布1.0版本以来的最重大的更新,其中包括泛型支持、基本类型的自动装箱、改进的循环、枚举类型、格式化I/O及可变参数。
Java虚拟机(JVM)是一个软件规范,相关软件有责任遵守它,以运行编译为Java字节码的程序。JVM是一个抽象的计算机制,并独立于操作系统,具有编译后的程序体积小、可防止执行恶意代码等特点,其没有预先假设基于任何特定的实现技术,不管是硬件还是操作系统。通常我们有几个常用的JVM软件,其32位与64位版本性能有所不同,但它们都包括JIT编译器和垃圾回收功能(GC)。
JIT编译器从JDK 1.0.2开始就是JVM的一部分了,当时Java只是用于浏览器客户端动态效果显示的一种技术。JIT编译器实现了程序执行之前Java字节码到硬件机器码的动态翻译,其背后的思想在于,相比Java源代码,字节码更小也更容易编译,但付出的代价是需要在Java字节码编译为机器码时花上一点时间,但与直接把Java源代码编译为机器码相比,时间还是少得多的。在32位与64位的JVM中,相应的JIT在把Java字节码编译为最终的机器码时,所花的时间稍微有所不同,但还能进行一些优化;另外,在IBM与Sun这两个版本的客户端与服务端程序上,总体性能也会有所不同。
垃圾回收是一种自动内存管理系统,它会收回对象不再需要使用的内存。从软件工程的角度来看,垃圾回收最大的一个好处就是--程序员不用再操心那些低级的内存管理细节了。同时,垃圾回收也去除了源代码中两个最大的bug--内存未释放(内存泄漏)与过早释放(指针崩溃)。内存回收在Java程序运行期间占了一个很重要的部分,因为它必须被经常执行以释放对象不再访问的Java堆。由于在32位与64位平台上,Java堆中的数据大小会有所变化,所以会因为32位与64位JVM的性能差异,导致相应垃圾回收的性能也会有所不同。
64位背景介绍
64位计算有几个重要组成部分,第一就是64位寻址;实际上,64位寻址是通过64位整数寄存器达到的(或RISC中所指的通用寄存器)。64位寄存器允许64位的指针装入到单个的寄存器中,而64位的指针,才是可以寻址访问更大内存的实质所在。当32位处理器只能访问到232字节或4GB内存时,64位处理器理论上却可寻址访问264字节或18×109GB内存。在现代的64位系统中,可寻址的内存的实际限制通常比理论值低一点,具体依赖于特定的硬件架构和操作系统,举例来说,在基于Linux的操作系统中,受限于当前Linux内核数据结构的设计,可寻址的内存最多为242字节或4096GB。
64位计算的第二个重要方面,就是64位整数运算。要提醒的是,这可不是简单地因为有了可存储更多更大整数量、更宽的64位整数寄存器而带来的必然结果;其最直接的影响就是对那些需要处理密集大数值整数运算的程序而言,可带来性能上的飞跃。
第三个方面--即64位计算的特性,是64位操作系统与程序的应用;相关的软件必须全面支持硬件的64位特性,包括64位寻址和运算。通常还有一些附带的好处,如,可操作更多更大的文件、管理更大的磁盘等等。
64位计算所带来的影响,目前已在许多程序中得到了体现,数据库服务器现在可寻址更大的内存,以维持更大的缓冲池、数据缓存、或在内存中进行排序以减少相关的I/O操作;也能给每个用户分配更多的内存、支持更多的用户、或对更大的数据文件进行操作;仿真或其他计算密集的程序也将从中受益,如,现在可以在内存中分配更大的数组了。最后,别忘了还有大量的Java程序--J2EE应用服务器--现在也能充分享受到64位计算所带来的好处了。
64位计算的主要缺点是,与它们32位的兄弟相比,64位二进制文件一般都更大,因此,最终生成的机器码体积也更大,在系统缓存与旁路转换缓存(TLB)大小不变的情况下,可能会同时降低两者的命中率,这就是说,在一定程度上性能会有所损失。
性能评测
此处用于测试32位与64位JVM性能的系统,是两台64位双CPU工作站,一台是基于AMD64技术的Opteron系统,而另一台是基于PowerPC64的Apple Power Mac G5,两台工作站都分别运行基于Linux的64位操作系统;受测试的JVM分别来自于IBM和Sun。将使用SPEC的SPECjvm98和SPECjbb2000来测试相应JVM的性能,其中SPECjvm98使用了以下项目测试客户端性能。
·_201_compress,一个流行的压缩程序。
·_202_jess,一个Java版的NASA CLIPS基于规则的专家系统。
·_209_db,数据管理基准测试软件。
·_213_javac,JDK Java编译器。
·_222_mpegaudio,一个MPEG-3音频解码器。
·_227_mtrt,一个对图像文件进行处理的双线程程序。
·_228_jack,一个分析程序生成器。
SPECjbb2000(Java商业基准程序)是一个用于服务端的基准测试程序,其模仿了三层体系结构,是一个通用类型的Java服务端应用程序。
通过运行SPECjvm98,以秒为单位记录了每个基准测试的运行时长,时间越短越好。所有SPECjvm98测试的堆大小因JVM而有所变化,从最小值16MB至最大值32MB。在SPECjbb2000测试中,记录了在三种不同堆大小时的每秒执行操作数,更高的值代表更高的性能。每一个测试程序都运行三次,取成绩最好的一次作为最后的结果。
图1与图2显示了在AMD64平台上,Linux版本的Sun Java 2 Standard Edition Development Kit 5.0 (J2SE 1.5.0)在SPECjvm98和SPECjbb2000中32位与64位的性能测试结果,在SPECjvm98测试中,只有三项--_201_compress、_222_mpegaudio、 _228_jack,在64位版本的JVM上比32位表现出更佳的性能。在SPECjbb2000中,64位版本的性能只在有足够堆大小的情况下,才表现出更高的性能,其中在堆大小为256MB时,因为某些活动数据在64位JVM版本中体积更大,导致垃圾回收动作更频繁,从而降低了程序性能。
图1 |
图2 |
图3 |
图4 |
图5 |
图6 |