一种基于ARM7的嵌入式Java虚拟机性能优化技术研究.doc

上传人:吴起龙 文档编号:1592083 上传时间:2018-12-26 格式:DOC 页数:12 大小:19.32KB
返回 下载 相关 举报
一种基于ARM7的嵌入式Java虚拟机性能优化技术研究.doc_第1页
第1页 / 共12页
一种基于ARM7的嵌入式Java虚拟机性能优化技术研究.doc_第2页
第2页 / 共12页
一种基于ARM7的嵌入式Java虚拟机性能优化技术研究.doc_第3页
第3页 / 共12页
亲,该文档总共12页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述

《一种基于ARM7的嵌入式Java虚拟机性能优化技术研究.doc》由会员分享,可在线阅读,更多相关《一种基于ARM7的嵌入式Java虚拟机性能优化技术研究.doc(12页珍藏版)》请在三一文库上搜索。

1、一种基于的嵌入式虚拟机性能优化技术研究Sun公司于2000年公布的J2ME/MIDP参考实现,采用解释执行字节码的Java虚拟机。与编译执行相比,解释执行的JVM在移动通信设备上具有显著的优点:虚拟机占用移动通信设备非易失性存储空间比较小;虚拟机运行时占用RAM空间比较小;解释执行核心代码量小;字节码占用RAM空间比较小;实现难度低、可移植性好。现有的具有J2ME/MIDP支持的移动通信设备大多是基于该参考实现。 目前针对Java虚拟机有多种性能优化技术,如基于编译运行的优化技术、基于解释运行的优化技术以及一些针对内存管理与垃圾回收方面的改良算法等。而基于解释运行的优化技术在保持了解释型虚拟机

2、结构简单、可移植性好的优点的同时,也有效地提高了解释型虚拟机的性能。 基于目前最常用的低功耗32位处理器ARM7及16位总线结构的主流手机平台,本文提出并实现了一个基于解释执行的嵌入式Java虚拟机性能优化方案。 1Java字节码的解释执行 Java字节码(Bytecode)在文献1中也被称为Java虚拟机指令集(Java Virtual Machine Instruction Set)。与具体的CPU指令集类似,Java字节码就是运行于Java虚拟机上的指令集。Java源程序在被执行之前,要先被编译成Java字节码,再运行于Java虚拟机上。每条Java字节码长度为一个字节(8 bits),

3、因此被称为字节码。字节码之后可能存在一个或多个字节的操作数。文献2详细定义了所有的标准Java字节码。 在Java虚拟机内部,采用了一个Interpreter来解释每个Bytecode的意义。如图1所示,Interpreter是个大循环,它一直不停地从PC所指到的内存空间抓取Bytecode,翻译成各种不同作业平台上相对应的操作,并执行这些操作。 字节码的执行流程如下:为程序计数器pc赋初值,进入解释循环。Switch指令取出pc指向的字节码,将pc加1;根据字节码的值跳转到对应的Case语句。Case语句后的解释程序执行字节码对应的操作。回到循环的开头,如果程序没有结束,则进行下一次Swit

4、chCase解释过程。 需要指出,Java字节码中大部分堆栈访问和运算指令所执行的操作是比较简单的。这些字节码所对应的解释程序通常只有15条C语句,对应的机器指令通常也只有几条到十几条。在这种情况下,SwitchCase的解释执行过程所增加的额外开销相当可观。从机器指令的角度来看,SwitchCase的开销包括:一次访存操作,读入pc指向的字节码;pc加1 操作;对字节码的值进行边界检查;一次访存操作,查找字节码在SwitchCase跳转表中对应的程序段入口;一次跳转操作到对应的Case程序段;在Case程序段执行完毕后,再进行一次跳转操作,回到循环开头。可以看出,SwitchCase的开销甚

5、至超过了某些字节码解释程序自身的开销。这种开销累积起来,对执行效率的影响相当大。 2适合移动通信设备的Direct Threaded Interpreter优化技术 基于解释运行的优化技术主要包括Threaded Interpreter3、Direct Threaded Interpreter4和Inlined Threaded Interpreter5。有实验表明5:Threaded Interpreter与SwitchCase解释器相比性能有一定提高,但提高幅度有限,约7%10%;Inlined Threaded Interpreter与SwitchCase解释器相比性能有很大提高,约15

6、0%300%,但内存占用太大;而Direct Threaded Interpreter较折中,与SwitchCase解释器相比,性能提高约40%100%,同时保持较少的内存占用。因此,本文主要考虑Direct Threaded Interpreter。 Threaded可译为线索化,是指解释器对相邻字节码的解释执行过程,通过一定的线索直接联系在一起,而不像SwitchCase那样,每解释完一条字节码都要重新经过由Switch进行解释分发。Direct Threaded Interpreter可以被译为直接线索化解释器。 Direct Threaded Interpreter的核心思想为:解释器

7、在运行字节码之前把字节码数组翻译为直接包含字节码对应解释程序入口的Threaded Code数组。在解释运行时不再访问原来的字节码数组,而是直接访问这个Threaded Code数组,只读入对应的处理程序入口地址。 从字节码数组到Threaded Code数组的翻译过程如图2所示。变换时,在Threaded Code数组中,将字节码操作码变换成对应处理程序的入口标号地址,操作数直接复制。其中,&BYTECODE_LABEL表示对Bytecode对应的解释程序入口标号BYTECODE_LABEL寻址。 Direct Threaded Interpreter的工作过程为:一个字节码解释执行完毕后,

8、使pc指针指向Threaded Code数组中下一条字节码解释程序入口标号地址。使用goto *pc语句直接跳转到下一条字节码对应解释程序入口处执行,执行完后使pc指针指向再下一条。如此往复,直到程序结束。Direct Threaded Interpreter工作过程的伪码如下: 与SwitchCase相比,Direct Threaded Interpreter省掉了以下的操作:每条字节码解释完毕后,到Switch的跳转指令;读入pc指向的字节码;Switch在查找跳转表之前对字节码的值进行边界检查的指令。 考虑到许多常用字节码本身的解释程序就很短(甚至不到10条机器指令),Direct Th

9、readed Interpreter的优化效果是相当明显的。文献5的实验结果表明,Direct Threaded Interpreter的速度比SwitchCase快40%100%。不过,由于需要额外的内存空间来存放解释程序的地址数组,Direct Threaded Interpreter的内存开销要大于SwitchCase(需要约四倍于字节码自身大小的内存空间)。 3针对ARM7平台的优化方案 针对目前手机常用的32位CPUARM7和16位总线平台的特点,对Direct Threaded Interpreter结构进行改造;同时采用一些其他优化技术提出新的优化方案,即16 bits Dire

10、ct Thread Interpreter。本文选择Sun公司开放源码的CLDC参考实现(以下简称CLDC RI)作为基础代码,在此基础上实现本文的优化方案。 在32位CPU上,标号地址(类型为void*)长度为32位,占用4 Bytes的存储器。所以,无论是操作码还是操作数,在翻译后都要占用4 Bytes的存储空间,即Threaded Code是以4 Bytes(32 bits)为一个单元的。从Direct Threaded Interpreter实现原理中可以看到,一个Bytecode单元(8 bits)与一个Threaded Code单元(32 bits)一一对应。使用Threaded

11、Code,内存占用扩大为原来的四倍;而且对于16位总线结构的硬件平台,每取得一个单元数据,均需要两次访存。特别对于操作数,每个Threaded Code单元只有最后八位是有意义的,其他部分都浪费掉了;使用时,还需要数据重组。 在字节码操作码方面,Sun公司Java虚拟机总共包含大约230条字节码指令。一条字节码所对应的解释程序本身很短,通常只有15条C语句,对应的机器指令也就只有几条到十几条。字节码解释程序入口地址间的跨度不大。实验表明:16位的整数足以表示任意两条字节码解释程序入口标号地址间的偏移量。操作数方面,可以考虑在翻译过程中,将操作数的若干个字节码合并在一条Threaded Code

12、单元中。这样既节约空间,又能避免使用时的数据重组,提高了效率。 综上所述,针对所采用的ARM7平台特点,改进Direct Threaded Interpreter,制定出一个16bits Direct Threaded Interpreter优化方案。 16 bits Direct Threaded Interpreter中,每一个Threaded Code单元是16位的。其变换原则为:将偏移所用的32位基地址保存在一个寄存器中。在Threaded Code数组中,将字节码变换成对应处理程序入口标号地址相对于基地址的偏移量。操作数的翻译:8 bits的操作数直接翻译为一个16 bits的数保存

13、;16 bits的操作数整合为一个16 bits的数保存;高16位一定为0的32位操作数整合为一个16 bits的数保存;其他32位操作数,整合为两个16 bits的数保存。在解释运行时,直接访问16 bits Threaded Code数组,不再访问字节码数组。通过指向16 bits Threaded Code数组的tc_pc指针,读入对应的处理程序入口地址的偏移量,再与寄存器中的基地址相加得到该处理程序入口地址,赋给pc指针。使用goto*pc语句,解释器跳转到字节码对应的解释程序执行。每个字节码解释执行完毕后,tc_pc指针指向Threaded Code数组中下一条字节码解释程序入口地址

14、的偏移量。翻译解释过程如图3所示。 与Direct Threaded Interpreter相比,16 bits Direct Threaded Interpreter有如下两个优点:提高效率。取得32位地址,以前需要两次访存操作, 现在仅需要一次访存和一次CPU操作。显然,访存操作所用时间远远大于CPU操作时间,在效率上有较大提高。节约空间。每个操作码的内存占用由原来的32 bits减少为16 bits;8 bits的操作数仅扩展为16 bits,减少了16 bits的空间浪费;16 bits和32 bits的操作数都不再有空间的浪费。内存占用只扩大了不到两倍。 以下的伪码简单表示了16 b

15、its Direct Threaded Interpreter的翻译过程: /*初始化地址偏移量表*/ opcode_entrie_offsetsOPCODE_1 = &OPCODE_1_LABEL base; opcode_entrie_offsetsOPCODE_2 = &OPCODE_2_LABEL base; opcode_entrie_offsetsOPCODE_3 = &OPCODE_3_LABEL base; /*将字节码翻译为16 bits Threaded Code */ uint8*pc = bytecodes; int bytecodes_length = length

16、of bytecodes; short*tc_pc = threadedCodes; while (bytecodes_length) if (IS_OPCODE(*pc) /* 该字节是操作码*/ swith(*pc) case OPCODE_NO_OPERAND : /* 属于无操作数的字节码操作码 */ *tc_pc = opcode_entrie_offsets*pc; /* 操作码翻译为解释程序入口地址偏移量*/ tc_pc+; /*调整指针 */ pc+; break; case OPCODE_1_OPERAND: /* 属于有1 Byte操作数的字节码操作码 */ *tc_pc

17、= opcode_entrie_offsets*pc; /* 操作码翻译为解释程序入口地址偏移量*/ *(tc_pc + 1) =*(pc + 1); /* 处理操作数,一个8 bits操作数,直接拷贝 */ bytecodes_length; tc_pc += 2; /* 调整指针 */ pc += 2; break; case OPCODE_2_OPERAND : /*属于有2 Bytes操作数的字节码操作码 */ *tc_pc = opcode_entrie_offsets*pc; *(tc_pc + 1) = (unsigned short)(*(pc + 1) 这里采取的方法是两次扫

18、描,即通过两次扫描实现字节码到Threaded Code的翻译。第一次扫描将Java字节码指令翻译为Threaded Code,并将字节码偏移量与Threaded Code偏移量的对应关系保存在一个数组中;第二次扫描则根据该偏移量对应关系数组来处理Threaded Code中的分支和跳转地址。图4表示了第一次翻译过程的结果,图中深色背景的单元格表示数组下标。tcode_offset数组中保存了字节码数组和Threaded Code数组的下标对应关系,tcode_offsetm=n表示字节码中偏移量为m的指令对应Threaded Code中偏移量为n的指令。 第二次扫描过程寻找Threaded

19、Code中的跳转指令,根据tcode_offset数组保存的对应关系来修改分支转移指令的操作数。如上例中,在第二次扫描发现BYTECODE_2是跳转指令,取得其跳转的相对偏移为8,原字节码的跳转目的为10。tcode_offset的序号与Bytecode的序号是一一对应的,通过tcode_offset找到BYTECODE_2及其跳转目的10在Threaded Code数组中对应的序号位置,分别为2和7。最后,将Threaded Code数组中序号为2的Threaded Code单元之后的操作数改为5。到此,BYTECODE_2这条跳转指令的相对跳转地址修改完毕,继续查看下一条指令是否为跳转指令

20、。 这样,通过两次扫描就完成了字节码到Threaded Code的翻译过程。 在此基础上,本文还采取了一些其他优化措施,如字节码合并、可抛弃Threaded Code、调整解释程序的排列顺序等。字节码合并主要包括:将某些不指定操作数类型的指令细分并改写为针对特定类型的指令;将常量操作数直接嵌入在Threaded Code中,减少一次查表的开销;合并某些功能相近或相同的指令。可抛弃Threaded Code是采用LRU(最近最久未用)表来管理专门用于存放Threaded Code的内存空间,进一步降低Threaded Code的内存占用。此外,Java虚拟机中定义的指令在Java程序中出现的频率

21、是不一样的。将使用频率高的指令解释程序安排在相邻的地址空间中,提高CPU指令Cache的命中率,进而改善虚拟机性能。 4性能比较 本文使用JBenchmark 2.0以及自行编写的综合测试案例,对运行在ARM7、16位总线的手机平台上的KVM进行了多次测试。为了比较与Direct Threaded Interpreter的性能差异,将之前实现的基于Direct Threaded Interpreter优化的KVM加入测试。表1列出了每组测试结果的平均值。其中,JBenchmark 2.0针对MIDP 2.0检测第二代Java设备的图像表现力,有五个小的测试项目,每个10 s。自行编写的测试案例

22、包含大量的循环、整数乘除法运算、对象分配和虚方法调用。 从JBenchmark 2.0的分数来看,采用了该优化方案的KVM的性能比RI和基于Direct Threaded Interpreter的KVM都要高;内存的占用也比基于Direct Threaded Interpreter的版本减少了。从测试案例的结果进行估算,采用本文优化方案的KVM的性能比RI高出约69%,比基于Direct Threaded Interpreter的版本高出约8%。 5结束语 本文介绍了Java字节码的解释执行, 详细分析了Direct Threaded Interpreter优化技术。在此基础上,针对目前最常用的ARM7、16位总线的手机平台提出并实现了一种改良的解释器优化方案,即16 bits Direct Threaded Interpreter。文中对16 bits Direct Threaded Interpreter优化方案进行了详细描述,并对Direct Threaded Interpreter及CLDC RI进行了性能对比工作。通过性能对比,说明了采用本优化方案能使Java虚拟机解释器性能得到比较显著的提高。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 其他


经营许可证编号:宁ICP备18001539号-1