利用虚拟机解决内存管理问题(来源:转载自电子工程专辑网站,http://www.eetchina.com) 虚拟机是运行在主操作系统顶层的软件层,使通讯程序、Java应用程序与任何底层硬件的改变互不相关。本文概述利用虚拟机解决内存管理问题的实现途径。 Kim Clohessy 将Java成功地移植到嵌入式系统的关键是虚拟机技术。Java虚拟机是一种软件,对Java程序而言,它表现为具有单一硬件和操作系统特性的软件“计算机”,它能够使采用Java编程语言编写的程序无需修改就可以运行在大多数操作系统和硬件平台上。 Java虚拟机是运行在主操作系统顶层的软件层,为Java程序提供单一的、一致的API。它将已编译的字节码文件作为类文件载入,这个动态载入
(图1)并链接附加的类文件的过程是根据需要进行的。在Java虚拟机提供的环境内获得所有的服务后,程序才执行。这使得Java程序在不同的计算结构和不同类型的嵌入式设备之间具备高度的可移植性。 Java程序用来获取服务的Java API是由Sun Microsystems公司定义的,它由分类组织成程序包的一套类所组成。Sun提供它自己的Java虚拟机版本,作为Java平台实现的一部分。Sun的版本通常代表了虚拟机的标准。但是在虚拟机幕后的技术并无秘密可言,开发独立于Sun版本的虚拟机是完全可能的。Sun的Java虚拟机是一个面向广泛应用的一般平台,并没有针对某种特殊的硬件或者应用程序做优化。 对于嵌入式系统的应用,虚拟机应该对小型、资源有限的设备进行优化。当无法获得所需的计算资源时,使用通用平台通常并不可行。在嵌入式系统中拥有一个稳定而且可定制的虚拟机是特别重要的,因为无数的处理器、实时操作系统(RTOS)和程序包选择会使设计决定变得复杂和耗费时间。虚拟机使通讯程序、Java应用程序与任何底层硬件的改变互不相关。
(图2)专为嵌入式系统优化的虚拟机提供设备间的应用程序可移植性,同时能够为全新和创新设计提供紧凑和高度灵活的程序包。使用虚拟机作为应用平台在市场周期、可靠性和生存周期成本方面有很大的优势。工程师不必考虑处理器和RTOS的差异就可以获得稳定和公共的平台,因此,在新一代产品或者该系统的后续系列产品开发中,仍然可重复使用专为某一系统开发的应用程序。 配备齐全的Java虚拟机工作平台比较大---完整的Java程序包多达10MB。通常,台式工作站需要有效的处理能力和内存以运行完整的Java虚拟机。这一事实可能给一些工程师造成错觉,即任何Java平台的实现对于任何嵌入式系统都一定过于庞大。 造成误解的原因有两点。首先,Java虚拟机的大部分功能对许多嵌入式系统来说是不需要的。比如,用户界面有限的小型手持式设备可能不需要多数的图形和窗口工具箱,而象网络路由器这样的设备根本不需要图形和窗口工具箱。对于小型、用途有限的应用,Java虚拟机的大小可以充分地减少,其大小的最小值完全取决于应用,而不必根据现有嵌入式设备的内存和存储器容量来考虑。第二,Java虚拟机比较大,从而模糊了Java程序通常远小于编译程序这一事实。如果将虚拟机、它支持特征代码的组件以及类库看作Java的“进入费”,那么应用代码可以被视为“有效载荷”。Java语言使小的有效载荷可以实现相同的功能,例如,一个简单的使用具备Motif界面的C++编制的“Hello, world”可执行拷贝(image)大约为0.5M,而用Java语言编写的同样的程序只有12KB。 当然,运行Java程序所需的虚拟机比起C++拷贝所需的内存开销要大大增加。仅仅对于单一的Java程序,在许多情况下内存开销可能会远远超过Java应用程序的小尺寸。但是在许多设计中可能会有超出常规的例外。在虚拟机的内存开销与应用软件的性能之间的平衡牵涉到以下因素: * 在设备上运行的应用程序数 * 这些应用程序的复杂度 * 应用程序是从高速设备(如硬盘驱动器或者闪存)还是低速设备(如modem)载入。 如果设备可以运行几个不同的应用程序,而且至少这些应用程序中存在一个复杂度适中的程序,或者如果应用程序是定期从服务器上下载的,则Java虚拟平台的系统开销是可以忍受的。在这些情况下,对整个内存和存储器的需求实际上比采用更为传统的语言编写时的需求要少。 IBM为嵌入式系统开发的VisualAge就是一种满足Java语言在嵌入式系统上执行需要的虚拟机。VisualAge支持在高度可定制平台上运行Java程序,具有选择出仅为目标设备所需的类库和支持文件的能力。如果运行给定程序需要一些组件,VisualAge具有从服务器动态下载组件的构架。虚拟机的新程序和升级文件同样可以根据需要下载。 在嵌入式设备中,或许使用标准Java语言的最大局限性在于缺乏确定内存历史状态的信息并无法保证实时响应。其原因主要是虚拟机具有自动内存分配和自动解除内存分配的功能。当说明一个变量后,Java虚拟机自动分配内存,并且周期性地调用程序以收集无用内存信息,而不是要求程序调用管理内存的函数。 内存回收的作用是搜索整个内存以寻找未引用内存并将其收入空闲内存列表。Java虚拟机利用内存回收的软件算法把不再使用的内存归还系统。这样使程序员不必手工将内存归还系统,也减少了程序中内存错误发生的可能性(图3)。
用于Java内存回收的标准方法称之为“保守法”。保守法检测内存以确定其是否包含有效的地址。大多数情况下这种方法是有效的,易于实现而且系统开销不大。但它并非一直有效,如果一个变量包含一个恰巧在有效地址范围内的整数,那么它将被认为有效而不被回收。 在台式机系统中,计算机关机前丢失一些内存字节并不算什么。但是在一个资源有限的嵌入式设备中,这种内存泄漏(memory leaks)将对稳定性造成严重影响。嵌入式虚拟机的内存回收器必须积极主动,不能沿用常规Java虚拟机中的保守收集算法。一个主动的虚拟机应有能力确定对象(objects)是否不再被引用且是否不再需要。 实现主动收集算法的方法有几种。一种方法是标识内存并使用引用计数。当引用计数达到0时,内存将被收回。另一种方法是扫描内存来发现未被引用的对象。虽然上述方法可防止资源有限的设备所无法承担的内存泄漏,但是比保守算法要占用稍微多一点系统开销。 由于虚拟机在进行内存回收时其它的Java任务无法运行,因而收集算法也会影响实时性能。内存回收过程的长短取决于不同的处理器,可能需要100ms或更多时间。如果应用程序有规则地分配对象并且不经常人为地迫使内存回收算法运行,Java虚拟机将在它认为合适的时候或在内存溢出时进行内存回收。 Sun的内存回收算法在正常情况下无法中断,这使它很难用于一些实时的技术方案。Sun版本的Java虚拟机有后台内存回收线程,可以在它认为系统空闲时启动收集进程。当内存回收器由此线程调用时,其它线程可以抢占,但它可能要很长时间才能完成抢占。最终,如果 Sun的Java虚拟机无法找到足够的内存来满足内存分配要求,它将执行不具备抢占能力的内存回收算法。 嵌入式内存回收算法必须能够被更高优先级的实时进程抢占,以便使嵌入式设备在必要时能提供实时响应。它还必须能够递增地工作,也就是说,它必须能够记忆在何处脱离并将在何处继续执行下去。否则,系统将在内存回收上花费过多的时间。 理想情况下,系统设计者应能选择内存回收算法以更好地满足系统要求。对于有较高的处理要求而实时响应不太重要的情况下,虚拟机可以采用较保守的算法。相反,如果实时响应很重要,可代之为采用递增内存回收的主动算法。在嵌入式设备领域内,这种灵活性至关重要,在此领域内完全不同的设计要针对完全不同的用途。 直到现在,嵌入式系统开发者仍然不得不等候Sun开发Java语言实时版本的要求,以便应用到现有的一种Java平台之中。这就引发了市场周期问题,因为Sun用了两年多来为个人和嵌入式Java实现定义规范。 但是兼容性的选择并不一定是备选方案,特别是在嵌入式领域。IBM的用于嵌入式系统的VisualAge提供了独立的虚拟机,据认为它既与Java虚拟机标准兼容,又可以用来从底层对嵌入式系统应用进行开发。 支持运行时刻环境的嵌入式系统的VisualAge包括可运行在Intel x86、PowerPC或MIPS微处理器上的QNX/Neutrino实时操作系统。嵌入式系统的VisualAge为在嵌入式设备(如寻呼机、移动电话、屏幕电话、数字机顶盒和汽车导航系统)上运行Java程序提供了具备适应能力的虚拟机。(图4)举例说明了在汽车设备中的嵌入式应用。
幸亏虚拟机包含了先进的内存回收技术和动态组件下载功能,嵌入式系统的VisualAge产品提供了既满足内存制约又满足当今嵌入式系统实时要求的能力。它还提供了可供开发者编译应用程序、在开发工作站上定制虚拟机以及下载所需组件到嵌入式目标设备的集成环境。 使用象VisualAge这样的虚拟机,向嵌入式开发者提供了设计和构造具备通讯功能的设备所需的工具,这些通讯功能可以下载并运行应用程序和新的平台组件,同时保持与Java平台的兼容性。设计虚拟机减少了与其他处理器和硬件设备的接口复杂性,而且可以缩短产品上市周期并缩短开发后续产品的时间。 欲了解更多信息,请联系作者:Kim Clohessy。 E-mail: [email protected]; Fax: 1-602-5696300
|