Java自从推出以来一直备受关注,不过在嵌入式系统设计师看来,其性能并不能令人满意。运行Java虚拟机(JVM)解释Java字节码,这种方式对大多数嵌入式应用来说占用空间过多,运行速度过慢。不过Sun的Java 2 Micro Edition(J2ME)改变了这种状况。
对嵌入式系统设计师来说,Java有许多优点。作为一门编程语言,Java允许面向对象编程,又没有C中存在的严重问题。Java运行时环境还提供了有用属性。Java提供的内存管理功能使得编程人员不必分配及释放内存。运行时环境甚至可以通过整合核心类库来简化程序分配。 但大多数嵌入式应用面临Java没有处理好的两大约束:没有足够的空间和时间。
那么,Java作为一种在C++基础上改进了的面向对象的语言,在嵌入式应用开发方面能挑大梁吗?能否为它自己撑起一片蔚蓝的天空呢?
一、为什么会是Java?
对于嵌入式系统来说,Java技术比C语言和汇编语言具有很明显的优越性。最显著的特点是减少了系统的开发和维护,增强了代码的重利用能力,提高了Java代码与系统原有代码的可整合性。
1. 提高开发效率和可维护性
在项目的整个生命周期中,Java环境大大的简化了开发和维护。由于目标环境是建立在一个虚拟机上,代码可以很容易的编写、调试、分析、更改、维护。加上将来要连接的外接设备,未来的系统可能比目前的嵌入式系统复杂很多。升级手册也许不会在整个项目的生命周期中都能起到作用。取而代之的是,硬件设备的可连接性使得能够远程管理模块,这样就保证了开发人员能在产品上增加新的性能,同时解决了在产品生产后软件升级和维护的问题。
2. 重复利用代码
由于嵌入式系统有特殊的需求,以及不同的专门硬件要协同工作,嵌入式软件开发者通常使用非常原始的方法来开发,有时每一个新的项目都要从头再来一遍。现在,随着嵌入式技术的成熟以及系统本身变得更大更优化,很多人开始对于把一个产品的模块甚至是全部的应用程序用到另一个产品感兴趣。这种可重新利用性使得"一次开发,多次利用"成为了可能。
Java环境使得一个模块可以只要做很少的工作就可以适应多个项目和平台。甚至包括有时客户需要一个新的目标板,或者采用新的硬件(CPU或外设)和软件,或者使用不同的Linux都可以进行移植。
3. 集成Java代码和源代码
使用源代码明显是指应用程序的多可用性以及代码的重利用能力。在Java应用中,一个设计很好的界面,或者虚拟机,或者是底层的硬件都可以很好的兼容到嵌入式系统中。尽管无法移植,对于很多功能和硬件界面来说,在本地环境下开发的代码也许仍然是最好的解决方案。在C、C++或者汇编语言中,加入标准的通信、接口模块、用户界面、安全特性会花费很多时间与金钱。与之相比较,Java的基本库本身就提供了这些东西甚至还更多,这样就可以加速开发。
二、Java碎片真的会有影响吗?
在使用JavaME CLDC进行移动电话开发时,人们经常会碰到碎片这个词。Java强调“一次开发,多次利用”,但碎片出现,却打破了这种传奇。于是,这就导致应用开发人员不得不在许多不同的设备进行应用程序的测试,甚至于不得不在应用程序中对某些特殊的设备进行一步客户化的工作。
对程序开发人员来说,碎片真是个恶梦,因为碎片平白无故的增添了代码量和测试工作量。当然,对移动电话持有者来说也不是什么好事,因为碎片消耗了设备的空间。不管怎么说,碎片对每个人来说都是件很讨厌的事情。
但对于嵌入开发者而,碎片又意味着什么呢?
首先来看看碎片产生的根源。移动电话行业标准本来给不同的产品预留了一定的自由空间,这初衷是好的。但事实上,这种预留的空间,却导致了不同产品之间的冲突,不能进行很好的兼容。这就是碎片产生的最根本原因。于是这种不兼容性进而升级到了Java实现的程序里。这正是Java想花大力气创建一个统一Java实现的原因所在,如JSR248,MSA(Mobile Service Architecture)的建立。
从嵌入式开发人员的角度来看,也许并没有这么糟糕。其实碎片并不会影响到嵌入式开发人员,因为已经可以确定设备之间的硬件是完全兼容的。如果使用的是原始语言像C/C++的话,嵌入式开发人员可以在任何地方来编写代码,并在不同的设备上进行代码的重用。
三、 Java平台的测试
如果采用Java来实现嵌入式设备开发,会不会碰到C/C++经常碰到的测试成本太高的难题呢?
当然,采用Java来开发的话,可以对软件进行多次的重复测试,尽管这不一定是必需的。而完全需要进行重复测试的只是那些新加的Java实现。如果是Java平台的合法用户的话,还可以使用Sun提供的TCK来进行程序兼容性的检测。如果付费的话,还有很多压力测试可供选择。只要能保证Java平台的正常运行并按Java的测试通过了的话,那么所开发的程序其可移植性是完全可以保证的。
当然,在此有必须有提醒一下只测试Java实现端口的开发人员。因为有一些端口的实现有可能是采用C/C++来编写的,这些必须测试。可以使用全新设备来对整个程序进行测试以达到这一目的。
1. 测试工具包
通过采用Java来进行编程,可以确保平台的APIs是否正确的工作。如果采用C/C++或直接对操作系统编程,则使用全新的设备时,无法保证APIs的正常性。由于这些问题取决于所采用的测试包的全面性和可靠性,因此,在开发阶段有可能发现不了它们,而在部署的阶段发现了它们时,问题已经扩散得超出控制范围了。而对于Java平台的测试,一般比较全面。所以,C/C++或直接对操作系统编程的问题能比较早的被发现并解决。
因此,采用Java平台时,其测试时间有可能跟使用C/C++来开发整个程序的时间差不多。但结果大大不同,使用Java平台时,其最差的测试效果往往可以与C/C++环境下最好的测试效果媲美。就测试的选择而言,采用Java平台时,可以使用Sun的TCK来确保程序对新设备的适用性,同时,还可以得到Java的其它测试包,不过是收费的。然而使用C/C++时,则只能依靠开发人员自己来保证程序对新设备的适应性了。
2. 端口兼容性
那么如何知道设备所依赖的操作系统端口是兼容的呢?没法知道,因为操作系统供应商通过没有测试它。除非所使用的设备是标准的硬件,没有进行任何的客户化工作,或是可以让操作系统提供商对这特殊的端口进行单独的测试。相样,采用Java平台时,这又是怎么的结果呢?可喜的是,由于Java平台的TCK已经做了这样的工作,因此,这可以更好的提高其兼容性。
总之,采用Java平台所需的测试,最差的情况也就跟采用原始语言(C/C++)一样,但大部分情况下,都优于后者。而且,更具有兼容性的保证。
四、Java很占内存吗?
使用Java平台进行嵌入式设备开发时,其对内在的使用量,会不会比使用原始语言如C/C++更大些呢?这取决于软件的复杂性。Java由于虚拟机和内库的原因,有可能会导致内存开销的增大。下面比较一下Java平台内存的占用情况(基于Sun的实现):
CLDC(Connected Limited Device Configuration,运算功能有限、电力有限的嵌入式装置,如PDA 、手机等):可工作于100K(RAM),JIT(Just In Time,即时编译技术)需要最大些。典型的部署要求500K-16M(RAM)。
CDC(Connected Device Configuration,运算能力相对较佳、并请在电力供应上相对比较充足的嵌入式装置,如冷气机、电冰箱等):VM约为250K,JIT小于300K,VM+JIT+基础类库约占2-2.5M.典型的部署要求:4M-32M.
当然,内存的占用量还取决于应用的大小及内在的使用情况。可以看出,其实Java平台不会占用太大的内存。但是,这只是问题的一半。另一半是,Java代码最后部署时是以类文件来部署的,它主要是包括字节码和元数据。通过对CVM数据的分析,可以看出,字节码占据着大概30%的数据量。而采用JIT编译的代码相对于字节码而言,可以发现,内存的占有量增加了,并有一个7-8倍的ARM指令集。由于,可以估计:
Java类转成字节码的速度≈1/30%≈3.3x;
原始语言转成字节码的速度≈7x.这意味着,Java代码的内存使用量约为原始语言代码的一半。当然这只是非常粗略的估算,但却是合理的估算。
使用Java的JIT后,只有那些使用频率高的代码才会被编译。而在系统中只是偶然被执行的代码则采用解释来编译。同时,JIT尽量使被编译的代码其内存占有量保持在一较小的范围内。对CVM(CDC所使用虚拟机),默认值为512K.而在一些较优秀的程序中,可以发现,其值为100K-300K.这也就是说,使用Java编写的程序,只有使用频率比较高的代码才导致内存占用的增加。相反,使用C/C++编写的程序,整个代码都需要进行编译。因此,不能说使用Java语言编写的程序占用的内存就会比使用C/C++编写的程序大。这决定于软件相对于平台代码的复杂度及大小。如果软件规模比较大,Java平台所消耗的内存远小于Java类文件简洁性节约的内存,这种情况下,使用Java平台将有利于节约内存。如果软件的规模比较小,则Java平台消耗的内存就比较明显了,可以考虑使用C/C++来开发,以节约内存。
五、 结论
Java语言最初的设计企图是想用于控制消费性电子产品,本为嵌入式设备而设计,但随着因特网的兴起,Java在台式机和服务器端的应用开发中取得了巨大的成功。Java在应用中充分展示其通用性与完全性等优势,而这在嵌入式设备的应用开发中是至关重要的,这使得Java重返嵌入式应用开发领域成为必然。STK Java卡和J2ME的成功应用昭示着Java在嵌入式系统应用开发中的美好前景。