一种基于ARM7的嵌入式Java虚拟机性能优化技术研究Word文档下载推荐.docx
- 文档编号:910945
- 上传时间:2023-04-29
- 格式:DOCX
- 页数:8
- 大小:19.11KB
一种基于ARM7的嵌入式Java虚拟机性能优化技术研究Word文档下载推荐.docx
《一种基于ARM7的嵌入式Java虚拟机性能优化技术研究Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《一种基于ARM7的嵌入式Java虚拟机性能优化技术研究Word文档下载推荐.docx(8页珍藏版)》请在冰点文库上搜索。
Java源程序在被执行之前,要先被编译成Java字节码,再运行于Java虚拟机上。
每条Java字节码长度为一个字节(8bits),因此被称为字节码。
字节码之后可能存在一个或多个字节的操作数。
文献[2]详细定义了所有的标准Java字节码。
在Java虚拟机内部,采用了一个Interpreter来解释每个Bytecode的意义。
如图1所示,Interpreter是个大循环,它一直不停地从PC所指到的内存空间抓取Bytecode,翻译成各种不同作业平台上相对应的操作,并执行这些操作。
字节码的执行流程如下:
①为程序计数器pc赋初值,进入解释循环。
②Switch指令取出pc指向的字节码,将pc加1;
根据字节码的值跳转到对应的Case语句。
③Case语句后的解释程序执行字节码对应的操作。
④回到循环的开头,如果程序没有结束,则进行下一次Switch-Case解释过程。
需要指出,Java字节码中大部分堆栈访问和运算指令所执行的操作是比较简单的。
这些字节码所对应的解释程序通常只有1~5条C语句,对应的机器指令通常也只有几条到十几条。
在这种情况下,Switch-Case的解释执行过程所增加的额外开销相当可观。
从机器指令的角度来看,Switch-Case的开销包括:
①一次访存操作,读入pc指向的字节码;
②pc加1操作;
③对字节码的值进行边界检查;
④一次访存操作,查找字节码在Switch-Case跳转表中对应的程序段入口;
⑤一次跳转操作到对应的Case程序段;
⑥在Case程序段执行完毕后,再进行一次跳转操作,回到循环开头。
可以看出,Switch-Case的开销甚至超过了某些字节码解释程序自身的开销。
这种开销累积起来,对执行效率的影响相当大。
2适合移动通信设备的DirectThreadedInterpreter优化技术
基于解释运行的优化技术主要包括ThreadedInterpre-ter[3]、DirectThreadedInterpreter[4]和InlinedThreadedInterpre-ter[5]。
有实验表明[5]:
ThreadedInterpreter与Switch-Case解释器相比性能有一定提高,但提高幅度有限,约7%~10%;
InlinedThreadedInterpreter与Switch-Case解释器相比性能有很大提高,约150%~300%,但内存占用太大;
而DirectThreadedInterpreter较折中,与Switch-Case解释器相比,性能提高约40%~100%,同时保持较少的内存占用。
因此,本文主要考虑DirectThreadedInterpreter。
Threaded可译为线索化,是指解释器对相邻字节码的解释执行过程,通过一定的线索直接联系在一起,而不像Switch-Case那样,每解释完一条字节码都要重新经过由Switch进行解释分发。
DirectThreadedInterpreter可以被译为直接线索化解释器。
DirectThreadedInterpreter的核心思想为:
解释器在运行字节码之前把字节码数组翻译为直接包含字节码对应解释程序入口的ThreadedCode数组。
在解释运行时不再访问原来的字节码数组,而是直接访问这个ThreadedCode数组,只读入对应的处理程序入口地址。
从字节码数组到ThreadedCode数组的翻译过程如图2所示。
变换时,在ThreadedCode数组中,将字节码操作码变换成对应处理程序的入口标号地址,操作数直接复制。
其中,&
&
BYTECODE_LABEL表示对Bytecode对应的解释程序入口标号BYTECODE_LABEL寻址。
DirectThreadedInterpreter的工作过程为:
一个字节码解释执行完毕后,使pc指针指向ThreadedCode数组中下一条字节码解释程序入口标号地址。
使用goto*pc语句直接跳转到下一条字节码对应解释程序入口处执行,执行完后使pc指针指向再下一条。
如此往复,直到程序结束。
DirectThreadedInterpreter工作过程的伪码如下:
与Switch-Case相比,DirectThreadedInterpreter省掉了以下的操作:
①每条字节码解释完毕后,到Switch的跳转指令;
②读入pc指向的字节码;
③Switch在查找跳转表之前对字节码的值进行边界检查的指令。
考虑到许多常用字节码本身的解释程序就很短(甚至不到10条机器指令),DirectThreadedInterpreter的优化效果是相当明显的。
文献[5]的实验结果表明,DirectThreadedInterpre-ter的速度比Switch-Case快40%~100%。
不过,由于需要额外的内存空间来存放解释程序的地址数组,DirectThreadedInterpreter的内存开销要大于Switch-Case(需要约四倍于字节码自身大小的内存空间)。
3针对ARM7平台的优化方案
针对目前手机常用的32位CPU――ARM7和16位总线平台的特点,对DirectThreadedInterpreter结构进行改造;
同时采用一些其他优化技术提出新的优化方案,即16bitsDirectThreadInterpreter。
本文选择Sun公司开放源码的CLDC参考实现(以下简称CLDCRI)作为基础代码,在此基础上实现本文的优化方案。
在32位CPU上,标号地址(类型为void*)长度为32位,占用4Bytes的存储器。
所以,无论是操作码还是操作数,在翻译后都要占用4Bytes的存储空间,即ThreadedCode是以4Bytes(32bits)为一个单元的。
从DirectThreadedInterpreter实现原理中可以看到,一个Bytecode单元(8bits)与一个ThreadedCode单元(32bits)一一对应。
使用ThreadedCode,内存占用扩大为原来的四倍;
而且对于16位总线结构的硬件平台,每取得一个单元数据,均需要两次访存。
特别对于操作数,每个ThreadedCode单元只有最后八位是有意义的,其他部分都浪费掉了;
使用时,还需要数据重组。
在字节码操作码方面,Sun公司Java虚拟机总共包含大约230条字节码指令。
一条字节码所对应的解释程序本身很短,通常只有1~5条C语句,对应的机器指令也就只有几条到十几条。
字节码解释程序入口地址间的跨度不大。
实验表明:
16位的整数足以表示任意两条字节码解释程序入口标号地址间的偏移量。
操作数方面,可以考虑在翻译过程中,将操作数的若干个字节码合并在一条ThreadedCode单元中。
这样既节约空间,又能避免使用时的数据重组,提高了效率。
综上所述,针对所采用的ARM7平台特点,改进DirectThreadedInterpreter,制定出一个16bitsDirectThreadedInterpreter优化方案。
16bitsDirectThreadedInterpreter中,每一个ThreadedCode单元是16位的。
其变换原则为:
①将偏移所用的32位基地址保存在一个寄存器中。
②在ThreadedCode数组中,将字节码变换成对应处理程序入口标号地址相对于基地址的偏移量。
③操作数的翻译:
8bits的操作数直接翻译为一个16bits的数保存;
16bits的操作数整合为一个16bits的数保存;
高16位一定为0的32位操作数整合为一个16bits的数保存;
其他32位操作数,整合为两个16bits的数保存。
在解释运行时,直接访问16bitsThreadedCode数组,不再访问字节码数组。
通过指向16bitsThreadedCode数组的tc_pc指针,读入对应的处理程序入口地址的偏移量,再与寄存器中的基地址相加得到该处理程序入口地址,赋给pc指针。
使用goto*pc语句,解释器跳转到字节码对应的解释程序执行。
每个字节码解释执行完毕后,tc_pc指针指向ThreadedCode数组中下一条字节码解释程序入口地址的偏移量。
翻译解释过程如图3所示。
与DirectThreadedInterpreter相比,16bitsDirectThreadedInterpreter有如下两个优点:
①提高效率。
取得32位地址,以前需要两次访存操作,现在仅需要一次访存和一次CPU操作。
显然,访存操作所用时间远远大于CPU操作时间,在效率上有较大提高。
②节约空间。
每个操作码的内存占用由原来的32bits减少为16bits;
8bits的操作数仅扩展为16bits,减少了16bits的空间浪费;
16bits和32bits的操作数都不再有空间的浪费。
内存占用只扩大了不到两倍。
以下的伪码简单表示了16bitsDirectThreadedInterpreter的翻译过程:
/*初始化地址偏移量表*/
opcode_entrie_offsets[OPCODE_1]=&
OPCODE_1_LABEL-base;
opcode_entrie_offsets[OPCODE_2]=&
OPCODE_2_LABEL-base;
opcode_entrie_offsets[OPCODE_3]=&
OPCODE_3_LABEL-base;
…
/*将字节码翻译为16bitsThreadedCode*/
uint8*pc=bytecodes[];
intbytecodes_length=lengthofbytecodes;
short*tc_pc=threadedCodes[];
while(bytecodes_length―){
if(IS_OPCODE(*pc)){/*该字节是操作码*/
swith(*pc){
caseOPCODE_NO_OPERAND:
/*属于无操作数的字节码操作码*/
*tc_pc=opcode_entrie_offsets[*pc];
/*操作码翻译为解释程序入口地址偏移量*/
tc_pc++;
/*调整指针*/
pc++;
break;
caseOPCODE_1_OPERAND:
/*属于有1Byte操作数的字节码操作码*/
*(tc_pc+1)=*(pc+1);
/*处理操作数,一个8bits操作数,直接拷贝*/
bytecodes_length―;
tc_pc+=2;
/*调整指针*/
pc+=2;
caseOPCODE_2_OPERAND:
/*属于有2Bytes操作数的字节码操作码*/
*(tc_pc+1)=((unsignedshort)(*(pc+1)) 这里采取的方法是两次扫描,即通过两次扫描实现字节码到ThreadedCode的翻译。
第一次扫描将Java字节码指令翻译为ThreadedCode,并将字节码偏移量与ThreadedCode偏移量的对应关系保存在一个数组中;
第二次扫描则根据该偏移量对应关系数组来处理ThreadedCode中的分支和跳转地址。
图4表示了第一次翻译过程的结果,图中深色背景的单元格表示数组下标。
tcode_offset[]数组中保存了字节码数组和ThreadedCode数组的下标对应关系,tcode_offset[m]=n表示字节码中偏移量为m的指令对应ThreadedCode中偏移量为n的指令。
第二次扫描过程寻找ThreadedCode中的跳转指令,根据tcode_offset[]数组保存的对应关系来修改分支转移指令的操作数。
如上例中,在第二次扫描发现BYTECODE_2是跳转指令,取得其跳转的相对偏移为8,原字节码的跳转目的为10。
tcode_offset的序号与Bytecode的序号是一一对应的,通过tcode_offset找到BYTECODE_2及其跳转目的10在ThreadedCode数组中对应的序号位置,分别为2和7。
最后,将ThreadedCode数组中序号为2的ThreadedCode单元之后的操作数改为5。
到此,BYTECODE_2这条跳转指令的相对跳转地址修改完毕,继续查看下一条指令是否为跳转指令。
这样,通过两次扫描就完成了字节码到ThreadedCode的翻译过程。
在此基础上,本文还采取了一些其他优化措施,如字节码合并、可抛弃ThreadedCode、调整解释程序的排列顺序等。
字节码合并主要包括:
将某些不指定操作数类型的指令细分并改写为针对特定类型的指令;
将常量操作数直接嵌入在ThreadedCode中,减少一次查表的开销;
合并某些功能相近或相同的指令。
可抛弃ThreadedCode是采用LRU(最近最久未用)表来管理专门用于存放ThreadedCode的内存空间,进一步降低ThreadedCode的内存占用。
此外,Java虚拟机中定义的指令在Java程序中出现的频率是不一样的。
将使用频率高的指令解释程序安排在相邻的地址空间中,提高CPU指令Cache的命中率,进而改善虚拟机性能。
4性能比较
本文使用JBenchmark2.0以及自行编写的综合测试案例,对运行在ARM7、16位总线的手机平台上的KVM进行了多次测试。
为了比较与DirectThreadedInterpreter的性能差异,将之前实现的基于DirectThreadedInterpreter优化的KVM加入测试。
表1列出了每组测试结果的平均值。
其中,JBenchmark2.0针对MIDP2.0检测第二代Java设备的图像表现力,有五个小的测试项目,每个10s。
自行编写的测试案例包含大量的循环、整数乘除法运算、对象分配和虚方法调用。
从JBenchmark2.0的分数来看,采用了该优化方案的KVM的性能比RI和基于DirectThreadedInterpreter的KVM都要高;
内存的占用也比基于DirectThreadedInterpreter的版本减少了。
从测试案例的结果进行估算,采用本文优化方案的KVM的性能比RI高出约69%,比基于DirectThreadedInterpreter的版本高出约8%。
5结束语
本文介绍了Java字节码的解释执行,详细分析了DirectThreadedInterpreter优化技术。
在此基础上,针对目前最常用的ARM7、16位总线的手机平台提出并实现了一种改良的解释器优化方案,即16bitsDirectThreadedInterpreter。
文中对16bitsDirectThreadedInterpreter优化方案进行了详细描述,并对DirectThreadedInterpreter及CLDCRI进行了性能对比工作。
通过性能对比,说明了采用本优化方案能使Java虚拟机解释器性能得到比较显著的提高。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 一种 基于 ARM7 嵌入式 Java 虚拟机 性能 优化 技术研究